Files
apache--tvm/tests/python/relax/test_transform_error_enrichment.py
T
wehub-resource-sync 26446540fa
Lint / lint (push) Waiting to run
CI / MacOS (push) Waiting to run
CI / Windows (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:36:25 +08:00

108 lines
4.7 KiB
Python

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Tests for pass-time error enrichment with TVMScript-rendered locations.
A pass body that throws an error carrying a VisitErrorContext (e.g. a relax op
validator) is caught by the leaf pass executor and re-thrown with the failing
pass name plus the offending location rendered as underlined TVMScript.
"""
import pytest
import tvm
import tvm.testing
from tvm import relax
from tvm.ir import IRModule
def _bad_matmul_module():
"""Build (programmatically, no TVMScript parse) a module whose `main` binds a
matmul of incompatible shapes [3, 4] x [5, 6]. The function carries a
placeholder return type so it constructs; Normalize re-infers and the
matmul validator fires during the pass."""
x = relax.Var("x", relax.TensorType([3, 4], "float32"))
y = relax.Var("y", relax.TensorType([5, 6], "float32"))
lv = relax.Var("lv")
body = relax.SeqExpr([relax.BindingBlock([relax.VarBinding(lv, relax.op.matmul(x, y))])], lv)
func = relax.Function([x, y], body, ret_ty=relax.TensorType([3, 6], "float32"), is_pure=True)
func = func.with_attr("global_symbol", "main")
return IRModule({relax.GlobalVar("main"): func})
@pytest.mark.skip_well_formed_check_before_transform
@pytest.mark.skip_well_formed_check_after_transform
def test_pass_error_renders_underlined_tvmscript():
"""End-to-end: a bad matmul through a function pass yields a message naming the
pass and an underlined TVMScript snippet of the offending binding."""
mod = _bad_matmul_module()
with pytest.raises(ValueError) as excinfo:
relax.transform.Normalize()(mod)
assert str(excinfo.value) == (
"Matmul requires the reduction length of the operands to be equal. However, the LHS x "
"has shape R.shape([3, 4]), while the RHS y has shape R.shape([5, 6]). The reduction "
"dimensions of T.int64(4) and T.int64(5) are not equal.\n\n"
"Error in pass: Normalize\n"
"Location (TVMScript):\n"
"Access path: <root>.body.blocks[0].bindings[0].value\n\n"
"# from tvm.script import relax as R\n\n"
"@R.function\n"
'def main(x: R.Tensor((3, 4), dtype="float32"), '
'y: R.Tensor((5, 6), dtype="float32")) -> R.Tensor((3, 6), dtype="float32"):\n'
" lv = R.matmul(x, y, out_dtype=None)\n"
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
" return lv"
)
@pytest.mark.skip_well_formed_check_before_transform
@pytest.mark.skip_well_formed_check_after_transform
def test_sequential_does_not_double_append():
"""Running the failing pass inside a Sequential must not enrich twice — the
Sequential wrapper does not guard, only the leaf pass does."""
mod = _bad_matmul_module()
seq = tvm.transform.Sequential([relax.transform.Normalize()])
with pytest.raises(ValueError) as excinfo:
seq(mod)
msg = str(excinfo.value)
assert msg.count("Location (TVMScript):") == 1
assert "Error in pass: Normalize" in msg
@pytest.mark.skip_well_formed_check_before_transform
@pytest.mark.skip_well_formed_check_after_transform
def test_error_without_resolvable_node_is_not_masked():
"""A pass that throws an error whose node is not findable in the module must
surface the original message without raising a printer/render error."""
@tvm.transform.module_pass(opt_level=0, name="ThrowUnresolvable")
class ThrowUnresolvable:
def transform_module(self, mod, ctx):
# A bare error with no VisitErrorContext payload -> nothing to resolve.
raise tvm.error.InternalError("deliberate failure with no resolvable location")
mod = _bad_matmul_module()
with pytest.raises(tvm.error.InternalError) as excinfo:
ThrowUnresolvable()(mod)
msg = str(excinfo.value)
assert "deliberate failure with no resolvable location" in msg
# No context => no location block appended, but also no crash.
assert "Location (TVMScript):" not in msg
if __name__ == "__main__":
tvm.testing.main()