-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
api: remove parameters field from Trait #2940
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,9 @@ | |
|
||
import abc | ||
from collections.abc import Iterator | ||
from dataclasses import dataclass, field | ||
from dataclasses import dataclass | ||
from enum import Enum, auto | ||
from typing import TYPE_CHECKING, Any, TypeVar, final | ||
from typing import TYPE_CHECKING, TypeVar, final | ||
|
||
from xdsl.utils.exceptions import VerifyException | ||
|
||
|
@@ -20,13 +20,9 @@ class OpTrait: | |
A trait attached to an operation definition. | ||
Traits can be used to define operation invariants, additional semantic information, | ||
or to group operations that have similar properties. | ||
Traits have parameters, which by default is just the `None` value. Parameters should | ||
always be comparable and hashable. | ||
Note that traits are the merge of traits and interfaces in MLIR. | ||
""" | ||
|
||
parameters: Any = field(default=None) | ||
|
||
def verify(self, op: Operation) -> None: | ||
"""Check that the operation satisfies the trait requirements.""" | ||
pass | ||
|
@@ -47,22 +43,20 @@ class ConstantLike(OpTrait): | |
class HasParent(OpTrait): | ||
"""Constraint the operation to have a specific parent operation.""" | ||
|
||
parameters: tuple[type[Operation], ...] | ||
op_types: tuple[type[Operation], ...] | ||
|
||
def __init__(self, *parameters: type[Operation]): | ||
if not parameters: | ||
raise ValueError("parameters must not be empty") | ||
super().__init__(parameters) | ||
def __init__(self, head_param: type[Operation], *tail_params: type[Operation]): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not super() init? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no super init here that would set the op types property, as far as I understand |
||
object.__setattr__(self, "op_types", (head_param, *tail_params)) | ||
|
||
def verify(self, op: Operation) -> None: | ||
parent = op.parent_op() | ||
if isinstance(parent, self.parameters): | ||
if isinstance(parent, self.op_types): | ||
return | ||
if len(self.parameters) == 1: | ||
if len(self.op_types) == 1: | ||
raise VerifyException( | ||
f"'{op.name}' expects parent op '{self.parameters[0].name}'" | ||
f"'{op.name}' expects parent op '{self.op_types[0].name}'" | ||
) | ||
names = ", ".join(f"'{p.name}'" for p in self.parameters) | ||
names = ", ".join(f"'{p.name}'" for p in self.op_types) | ||
raise VerifyException(f"'{op.name}' expects parent op to be one of {names}") | ||
|
||
|
||
|
@@ -73,18 +67,18 @@ class HasAncestor(OpTrait): | |
parent. | ||
""" | ||
|
||
parameters: tuple[type[Operation], ...] | ||
op_types: tuple[type[Operation], ...] | ||
|
||
def __init__(self, head_param: type[Operation], *tail_params: type[Operation]): | ||
super().__init__((head_param, *tail_params)) | ||
object.__setattr__(self, "op_types", (head_param, *tail_params)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
|
||
def verify(self, op: Operation) -> None: | ||
if self.get_ancestor(op) is None: | ||
if len(self.parameters) == 1: | ||
if len(self.op_types) == 1: | ||
raise VerifyException( | ||
f"'{op.name}' expects ancestor op '{self.parameters[0].name}'" | ||
f"'{op.name}' expects ancestor op '{self.op_types[0].name}'" | ||
) | ||
names = ", ".join(f"'{p.name}'" for p in self.parameters) | ||
names = ", ".join(f"'{p.name}'" for p in self.op_types) | ||
raise VerifyException( | ||
f"'{op.name}' expects ancestor op to be one of {names}" | ||
) | ||
|
@@ -98,7 +92,7 @@ def walk_ancestors(self, op: Operation) -> Iterator[Operation]: | |
|
||
def get_ancestor(self, op: Operation) -> Operation | None: | ||
ancestors = self.walk_ancestors(op) | ||
matching_ancestors = (a for a in ancestors if isinstance(a, self.parameters)) | ||
matching_ancestors = (a for a in ancestors if isinstance(a, self.op_types)) | ||
return next(matching_ancestors, None) | ||
|
||
|
||
|
@@ -133,6 +127,7 @@ def verify(self, op: Operation) -> None: | |
) | ||
|
||
|
||
@dataclass(frozen=True) | ||
class SingleBlockImplicitTerminator(OpTrait): | ||
""" | ||
Checks the existence of the specified terminator to an operation which has | ||
|
@@ -144,7 +139,7 @@ class SingleBlockImplicitTerminator(OpTrait): | |
https://mlir.llvm.org/docs/Traits/#single-block-with-implicit-terminator | ||
""" | ||
|
||
parameters: type[Operation] | ||
op_type: type[Operation] | ||
|
||
def verify(self, op: Operation) -> None: | ||
for region in op.regions: | ||
|
@@ -156,13 +151,13 @@ def verify(self, op: Operation) -> None: | |
if (last_op := block.last_op) is None: | ||
raise VerifyException( | ||
f"'{op.name}' contains empty block instead of at least " | ||
f"terminating with {self.parameters.name}" | ||
f"terminating with {self.op_type.name}" | ||
) | ||
|
||
if not isinstance(last_op, self.parameters): | ||
if not isinstance(last_op, self.op_type): | ||
raise VerifyException( | ||
f"'{op.name}' terminates with operation {last_op.name} " | ||
f"instead of {self.parameters.name}" | ||
f"instead of {self.op_type.name}" | ||
) | ||
|
||
|
||
|
@@ -181,11 +176,11 @@ def ensure_terminator(op: Operation, trait: SingleBlockImplicitTerminator) -> No | |
if ( | ||
(last_op := block.last_op) is not None | ||
and last_op.has_trait(IsTerminator) | ||
and not isinstance(last_op, trait.parameters) | ||
and not isinstance(last_op, trait.op_type) | ||
): | ||
raise VerifyException( | ||
f"'{op.name}' terminates with operation {last_op.name} " | ||
f"instead of {trait.parameters.name}" | ||
f"instead of {trait.op_type.name}" | ||
) | ||
|
||
from xdsl.builder import ImplicitBuilder | ||
|
@@ -200,7 +195,7 @@ def ensure_terminator(op: Operation, trait: SingleBlockImplicitTerminator) -> No | |
IsTerminator | ||
): | ||
with ImplicitBuilder(block): | ||
trait.parameters.create() | ||
trait.op_type.create() | ||
|
||
|
||
class IsolatedFromAbove(OpTrait): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a breaking change, but the fix is just a couple of backspaces to delete the comma and instantiate the class instead of passing the parameters separately