Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Covariance and contravariance problem?#2042

Unanswered
hunterhogan asked this question inQ&A
Discussion options

Analyzing a diagnostic error

I think I finally understand the following situation. Can someone either correct my misunderstandings or shore up the concepts I describe?

Error and troubleshooting

Given this TypeAlias and this (edited) diagnostic error:

typehasDOTvalue_exprOrNone=ast.AnnAssign|ast.Return|ast.Yield...Argumentoftype"(node: hasDOTvalue_exprOrNone) -> (ast.expr | None)"cannotbeassignedtoparameter"doThat"oftype"(ast.Return) -> (ast.Tuple | None)"infunction"__init__"

If I change the argument type, the error goes away.

From

(ast.Return)-> (ast.Tuple|None)

To

(ast.Return)-> (ast.expr|None)

That is still not identical to

(node:hasDOTvalue_exprOrNone)-> (ast.expr|None)

But there isn't an error.

Analysis

So, I think this means

  1. ast.Return is kosher because I can pass aCallable that has a parameter ofhasDOTvalue_exprOrNone or any subset ofhasDOTvalue_exprOrNone, which I think is called "covariance."
  2. ast.Tuple | None is not kosher because the passedCallable must be able to handle all possible return types, which isast.expr | None, and whileast.Tuple is a subclass ofast.expr, the problem is that the passed function does not handle all possible returns: i.e., the other subclasses ofast.expr. I think this is called "contravariance."
Full error message

Argumentoftype "Overload[    (node:hasDOTvalue_boolOrNone)-> (bool|None)    , (node:hasDOTvalue_ConstantValueType)->ConstantValueType, (node:hasDOTvalue_expr)->expr    , (node:hasDOTvalue_exprOrNone)-> (expr|None)]"cannotbeassignedtoparameter"doThat"oftype"(Return) -> (Tuple | None)"infunction"__init__"  Nooverloadedfunctionmatches type"(Return) -> (Tuple | None)"

TypeAlias

typehasDOTvalue_boolOrNone=ast.MatchSingletontypehasDOTvalue_ConstantValueType=ast.ConstanttypehasDOTvalue_expr=ast.Assign|ast.Attribute|ast.AugAssign|ast.Await|ast.DictComp|ast.Expr|ast.FormattedValue \|ast.keyword|ast.MatchValue|ast.NamedExpr|ast.Starred|ast.Subscript|ast.TypeAlias|ast.YieldFromtypehasDOTvalue_exprOrNone=ast.AnnAssign|ast.Return|ast.YieldtypehasDOTvalue=hasDOTvalue_boolOrNone|hasDOTvalue_ConstantValueType|hasDOTvalue_expr|hasDOTvalue_exprOrNone

Code snippet

astTuple:ast.Tuple=raiseIfNone(NodeTourist[ast.Return,ast.Tuple|None](findThis=Be.Return.valueIs(Be.Tuple),doThat=Then.extractIt(DOT.value)).captureLastMatch(ingredientsFunction.astFunctionDef))

raiseIfNone

defraiseIfNone[TypeSansNone](returnTarget:TypeSansNone|None,errorMessage:str|None=None)->TypeSansNone:ifreturnTargetisNone:raiseValueError(errorMessage)returnreturnTarget

NodeTourist

=typing_TypeVar('木',bound=ast.AST,covariant=True)# "mu"归个=typing_TypeVar('归个',covariant=True)# "gui-ge"classNodeTourist(ast.NodeVisitor,Generic[,归个]):def__init__(self,findThis:Callable[[ast.AST],TypeIs[]|bool],doThat:Callable[[],归个])->None:self.findThis=findThisself.doThat=doThatself.nodeCaptured:归个|None=Nonedefvisit(self,node:ast.AST)->None:ifself.findThis(node):self.nodeCaptured=self.doThat(cast("木",node))self.generic_visit(node)defcaptureLastMatch(self,node:ast.AST)->归个|None:self.nodeCaptured=Noneself.visit(node)returnself.nodeCaptured

Then

classThen:@staticmethoddefextractIt[](node:)->:returnnode

DOT

classDOT:@staticmethod@overloaddefvalue(node:hasDOTvalue_boolOrNone)->bool|None:...@staticmethod@overloaddefvalue(node:hasDOTvalue_ConstantValueType)->ConstantValueType:...@staticmethod@overloaddefvalue(node:hasDOTvalue_expr)->ast.expr:...@staticmethod@overloaddefvalue(node:hasDOTvalue_exprOrNone)->ast.expr|None:...@staticmethoddefvalue(node:hasDOTvalue)->ast.expr|bool|ConstantValueType|None:returnnode.value

Follow-up: new paradigm?

If I am right, then I am pretty sure there is no way to tweak my current system of checking and passing type information: in some areas, I need a new paradigm to transfer type information. I have no idea, however, what I can do in this case.

The predicate has the type information (i.e.,node.value has typeast.Tuple), but I am not aware of any mechanism for transferring that information from the predicate to the action (doThat). If there is a mechanism, I am nearly certain I am not capturing the information in the predicate. I useTypeIs to capture the type ofnode, but even though I check the type of the attribute ofnode (i.e.,node.value), I don't think I am capturing the information, and I don't know how to capture it.

You must be logged in to vote

Replies: 1 comment

Comment options

2.ast.Tuple | None is not kosher because the passedCallable must be able to handle all possible return types, which isast.expr | None, and whileast.Tuple is a subclass ofast.expr, the problem is that the passed function does not handle all possible returns: i.e., the other subclasses ofast.expr. I think this is called "contravariance."

This is not quite right. I think I need to frame it from a different perspective.

Pylance is saying:

  1. You assigned a Callable that might returnast.expr | None,
  2. but you wrote that you expect a return ofast.Tuple " None.

Pylance is implying: That's a problem because there are values that could beast.expr without beingast.Tuple.

Follow-up: new paradigm?

Therefore, I guess I want to find a way to "narrow" the expected return type fromast.expr toast.Tuple. The overload definitions effectively narrow the expected return type fromast.expr | bool | ConstantValueType | None toast.expr | None andraiseIfNone effectively narrows that toast.expr. The only way I know to narrow it further would require ~1800 definitions covering each combination of: ast.class.attribute * (each possible type in the ast.class.attribute's annotation, including each subclass of an abstractast.AST subclass). I don't think that is a good idea, but I could easily generate the code.

idk.

You must be logged in to vote
0 replies
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Category
Q&A
Labels
None yet
1 participant
@hunterhogan

[8]ページ先頭

©2009-2025 Movatter.jp