chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
# 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()
|
||||
Reference in New Issue
Block a user