Skip to content

Commit 009c352

Browse files
committed
GR-36195: ix type hint errors when annotations are imported from __future__
1 parent 1bce562 commit 009c352

File tree

8 files changed

+144
-13
lines changed

8 files changed

+144
-13
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/parser/FuncDefTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ public void functionDef22() throws Exception {
203203
"print(test())\n");
204204
}
205205

206+
@Test
207+
public void annotations01() throws Exception {
208+
checkScopeAndTree();
209+
}
210+
206211
@Test
207212
public void decorator01() throws Exception {
208213
checkScopeAndTree();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from __future__ import annotations
2+
3+
4+
def b(x: int | str) -> int | str:
5+
return 10
6+
7+
print(b.__annotations__)
8+
9+
x: int | str = 10
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Scope: []
2+
Kind: Module
3+
FrameDescriptor: Empty
4+
CellVars: Empty
5+
FreeVars: Empty
6+
Scope: b
7+
Kind: Function
8+
FrameDescriptor: [x, <return_val>]
9+
CellVars: Empty
10+
FreeVars: Empty
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
ModuleRootNode Name: <module 'annotations01'> SourceSection: [0,130]`from __future__ impo...`
2+
Signature: varArgs=False, varKeywordArgs=False, noArguments=True, positionalOnly=True, requiresKeywordArgs=False
3+
FreeVars: None
4+
NeedsCellFrame: False
5+
FrameDescriptor: Empty
6+
Documentation: None
7+
InnerRootNode SourceSection: [0,130]`from __future__ impo...`
8+
ExpressionWithSideEffects SourceSection: [0,129]`from __future__ impo...`
9+
ImportFromNode SourceSection: [0,34]`from __future__ impo...`
10+
Importee: __future__
11+
Level: 0
12+
FromList: annotations
13+
WriteNameNodeGen SourceSection: None
14+
Identifier: annotations
15+
EmptyNode SourceSection: None
16+
IsBuiltinClassProfile SourceSection: None
17+
GetClassNodeGen SourceSection: None
18+
IsBuiltinClassProfile SourceSection: None
19+
GetClassNodeGen SourceSection: None
20+
WriteNameNodeGen SourceSection: [37,86]`def b(x: int | str) ...`
21+
Identifier: b
22+
FunctionDefinitionNode Name: b SourceSection: None
23+
Arguments: None
24+
KwArguments: None
25+
Documentation: None
26+
FreeVarSlots: None
27+
ExecutionSlots:
28+
FreeVarsSlots: None
29+
CellVarsSlots: None
30+
FunctionRootNode SourceSection: [37,86]`def b(x: int | str) ...`
31+
Name: b
32+
Signature: varArgs=False, varKeywordArgs=False, noArguments=False, positionalOnly=True, requiresKeywordArgs=False
33+
Param Names: x
34+
CelVars: None
35+
FreeVars: None
36+
NeedsCellFrame: False
37+
FrameDescriptor: 2 slots [x, <return_val>]
38+
ExecutionSlots:
39+
FreeVarsSlots: None
40+
CellVarsSlots: None
41+
InnerRootNode SourceSection: [37,86]`def b(x: int | str) ...`
42+
ReturnTargetNode SourceSection: [37,86]`def b(x: int | str) ...`
43+
Body: BlockNode SourceSection: None
44+
WriteLocalVariableNodeGen SourceSection: None
45+
Identifier: x
46+
Frame: [0,x,Illegal]
47+
ArgumentExpressionNode SourceSection: None
48+
ReadIndexedArgumentNodeGen SourceSection: None
49+
Index: 0
50+
FunctionBodyNode SourceSection: [75,84]`return 10`
51+
FrameReturnNode SourceSection: [75,84]`return 10`
52+
IntegerLiteralNode SourceSection: [82,84]`10`
53+
Value: 10
54+
Return Expresssion: ReadLocalVariableNodeGen SourceSection: None
55+
Frame: [1,<return_val>,Object]
56+
ExpressionStatementNode SourceSection: [86,110]`print(b.__annotation...`
57+
PythonCallUnary SourceSection: [86,110]`print(b.__annotation...`
58+
CallUnaryMethodNodeGen SourceSection: None
59+
ReadNameNodeGen SourceSection: [86,91]`print`
60+
Identifier: print
61+
IsBuiltinClassProfile SourceSection: None
62+
GetClassNodeGen SourceSection: None
63+
GetAttributeNode SourceSection: [92,109]`b.__annotations__`
64+
GetFixedAttributeNodeGen SourceSection: None
65+
Key: __annotations__
66+
LookupAndCallNonReversibleBinaryNodeGen SourceSection: None
67+
Op: __getattribute__
68+
ReadNameNodeGen SourceSection: [92,93]`b`
69+
Identifier: b
70+
IsBuiltinClassProfile SourceSection: None
71+
GetClassNodeGen SourceSection: None
72+
ExpressionWithSideEffects SourceSection: None
73+
WriteNameNodeGen SourceSection: [112,129]`x: int | str = 10`
74+
Identifier: x
75+
IntegerLiteralNode SourceSection: [127,129]`10`
76+
Value: 10
77+
SetItemNodeGen SourceSection: [0,0]Empty
78+
ReadNameNodeGen SourceSection: None
79+
Identifier: __annotations__
80+
IsBuiltinClassProfile SourceSection: None
81+
GetClassNodeGen SourceSection: None
82+
StringLiteralNode SourceSection: [0,0]Empty
83+
StringLiteralNode SourceSection: [115,124]`int | str`
84+
EmptyNode SourceSection: None

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public abstract class BuiltinNames {
5454
public static final String __MAIN__ = "__main__";
5555
public static final String __BUILTINS__ = "__builtins__";
5656
public static final String __DEBUG__ = "__debug__";
57+
public static final String __FUTURE__ = "__future__";
5758

5859
// sys
5960
public static final String TRACEBACKLIMIT = "tracebacklimit";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/PythonSSTNodeFactory.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import com.oracle.graal.python.parser.ScopeInfo.ScopeKind;
6565
import com.oracle.graal.python.parser.sst.AnnAssignmentSSTNode;
6666
import com.oracle.graal.python.parser.sst.AnnotationSSTNode;
67+
import com.oracle.graal.python.parser.sst.ArgDefListBuilder;
6768
import com.oracle.graal.python.parser.sst.ArgListBuilder;
6869
import com.oracle.graal.python.parser.sst.AssignmentSSTNode;
6970
import com.oracle.graal.python.parser.sst.AugAssignmentSSTNode;
@@ -104,6 +105,8 @@
104105
import com.oracle.truffle.api.source.Source;
105106
import com.oracle.truffle.api.source.SourceSection;
106107

108+
import static com.oracle.graal.python.nodes.BuiltinNames.__FUTURE__;
109+
107110
public final class PythonSSTNodeFactory {
108111

109112
/**
@@ -118,6 +121,7 @@ public interface FStringExprParser {
118121
private final Source source;
119122
private final PythonParser.ParserErrorCallback errors;
120123
private FStringExprParser fStringExprParser;
124+
private boolean futureAnnotations = false;
121125

122126
public PythonSSTNodeFactory(PythonParser.ParserErrorCallback errors, Source source, FStringExprParser fStringExprParser) {
123127
this.errors = errors;
@@ -163,6 +167,9 @@ public SSTNode createImport(String name, String asName, int startOffset, int end
163167
public SSTNode createImportFrom(String from, String[][] asNames, int startOffset, int endOffset) {
164168
if (asNames != null) {
165169
for (String[] asName : asNames) {
170+
if (from.equals(__FUTURE__) && asName[0].equals("annotations")) {
171+
futureAnnotations = true;
172+
}
166173
scopeEnvironment.createLocal(asName[1] == null ? asName[0] : asName[1]);
167174
}
168175
} else {
@@ -174,6 +181,20 @@ public SSTNode createImportFrom(String from, String[][] asNames, int startOffset
174181
return new ImportFromSSTNode(scopeEnvironment.getCurrentScope(), from, asNames, startOffset, endOffset);
175182
}
176183

184+
public SSTNode createAnnotationType(SSTNode type) {
185+
SSTNode annotType = type;
186+
if (futureAnnotations) {
187+
final String value = source.getCharacters().subSequence(type.getStartOffset() - 1, type.getEndOffset() + 1).toString();
188+
annotType = createStringLiteral(new String[]{value}, type.getStartOffset(), type.getEndOffset());
189+
}
190+
return annotType;
191+
}
192+
193+
public FunctionDefSSTNode createFunctionDef(ScopeInfo functionScope, String name, String enclosingClassName, ArgDefListBuilder argBuilder, SSTNode body, SSTNode resultAnnotation, int startOffset, int endOffset) {
194+
SSTNode annotation = createAnnotationType(resultAnnotation);
195+
return new FunctionDefSSTNode(functionScope, name, enclosingClassName, argBuilder, body, annotation, startOffset, endOffset);
196+
}
197+
177198
public String mangleNameInCurrentScope(String name) {
178199
if (cannotBeMangled(name)) {
179200
return name;
@@ -340,6 +361,7 @@ public SSTNode createAnnAssignment(AnnotationSSTNode annotation, SSTNode rhs, in
340361
}
341362

342363
public AnnotationSSTNode createAnnotation(SSTNode lhs, SSTNode type, int start, int end) {
364+
SSTNode annotType = createAnnotationType(type);
343365
// checking if the annotation has the right target
344366
if (!(lhs instanceof VarLookupSSTNode || lhs instanceof GetAttributeSSTNode || lhs instanceof SubscriptSSTNode)) {
345367
if (lhs instanceof CollectionSSTNode) {
@@ -355,7 +377,7 @@ public AnnotationSSTNode createAnnotation(SSTNode lhs, SSTNode type, int start,
355377
if (!scopeEnvironment.getCurrentScope().hasAnnotations()) {
356378
scopeEnvironment.getCurrentScope().setHasAnnotations(true);
357379
}
358-
return new AnnotationSSTNode(lhs, type, start, end);
380+
return new AnnotationSSTNode(lhs, annotType, start, end);
359381
}
360382

361383
public SSTNode createAugAssignment(SSTNode lhs, String operation, SSTNode rhs, int startOffset, int endOffset) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/antlr/Python3.g4

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,11 @@ funcdef
580580
}
581581
s = suite
582582
{
583-
SSTNode funcDef = new FunctionDefSSTNode(scopeEnvironment.getCurrentScope(), name, enclosingClassName, $parameters.result, optimize($s.result), resultType, getStartIndex(_localctx), getStopIndex(((FuncdefContext)_localctx).s));
584-
scopeEnvironment.popScope();
585-
loopState = savedLoopState;
586-
push(funcDef);
587-
}
583+
SSTNode funcDef = factory.createFunctionDef(scopeEnvironment.getCurrentScope(), name, enclosingClassName, $parameters.result, optimize($s.result), resultType, getStartIndex(_localctx), getStopIndex(((FuncdefContext)_localctx).s));
584+
scopeEnvironment.popScope();
585+
loopState = savedLoopState;
586+
push(funcDef);
587+
}
588588
;
589589

590590
parameters returns [ArgDefListBuilder result]
@@ -639,7 +639,7 @@ defparameter [ArgDefListBuilder args]
639639
if (name != null) {
640640
name = factory.mangleNameInCurrentScope(name);
641641
}
642-
ArgDefListBuilder.AddParamResult result = args.addParam(name, type, defValue);
642+
ArgDefListBuilder.AddParamResult result = args.addParam(name, factory.createAnnotationType(type), defValue);
643643
switch(result) {
644644
case NONDEFAULT_FOLLOWS_DEFAULT:
645645
throw new PythonRecognitionException("non-default argument follows default argument", this, _input, $ctx, getCurrentToken());

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/antlr/Python3Parser.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,11 +1172,11 @@ public final FuncdefContext funcdef() throws RecognitionException {
11721172
setState(277);
11731173
_localctx.s = suite();
11741174

1175-
SSTNode funcDef = new FunctionDefSSTNode(scopeEnvironment.getCurrentScope(), name, enclosingClassName, _localctx.parameters.result, optimize(_localctx.s.result), resultType, getStartIndex(_localctx), getStopIndex(_localctx.s));
1176-
scopeEnvironment.popScope();
1177-
loopState = savedLoopState;
1178-
push(funcDef);
1179-
1175+
SSTNode funcDef = factory.createFunctionDef(scopeEnvironment.getCurrentScope(), name, enclosingClassName, _localctx.parameters.result, optimize(_localctx.s.result), resultType, getStartIndex(_localctx), getStopIndex(_localctx.s));
1176+
scopeEnvironment.popScope();
1177+
loopState = savedLoopState;
1178+
push(funcDef);
1179+
11801180
}
11811181
}
11821182
catch (RecognitionException re) {
@@ -1690,7 +1690,7 @@ public final DefparameterContext defparameter(ArgDefListBuilder args) throws Rec
16901690
if (name != null) {
16911691
name = factory.mangleNameInCurrentScope(name);
16921692
}
1693-
ArgDefListBuilder.AddParamResult result = args.addParam(name, type, defValue);
1693+
ArgDefListBuilder.AddParamResult result = args.addParam(name, factory.createAnnotationType(type), defValue);
16941694
switch(result) {
16951695
case NONDEFAULT_FOLLOWS_DEFAULT:
16961696
throw new PythonRecognitionException("non-default argument follows default argument", this, _input, _localctx, getCurrentToken());

0 commit comments

Comments
 (0)