1# Copyright 2021, Kay Hayen, mailto:kay.hayen@gmail.com 2# 3# Part of "Nuitka", an optimizing Python compiler that is compatible and 4# integrates with CPython, but also works on its own. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18""" The type1 node. 19 20This one just determines types. It's great for optimization. We may be able to 21predict its value, but knowing it. In that case, we have a built-in name 22reference for that type to convert to, or when checking the result of it, we 23will then know it's limited after the fact. 24 25""" 26 27from nuitka.Builtins import builtin_names 28 29from .BuiltinRefNodes import ( 30 ExpressionBuiltinAnonymousRef, 31 ExpressionBuiltinRef, 32 makeExpressionBuiltinRef, 33) 34from .ExpressionBases import ( 35 ExpressionBuiltinSingleArgBase, 36 ExpressionChildHavingBase, 37 ExpressionChildrenHavingBase, 38) 39from .NodeBases import SideEffectsFromChildrenMixin 40from .NodeMakingHelpers import wrapExpressionWithNodeSideEffects 41from .shapes.BuiltinTypeShapes import tshape_bool, tshape_type 42 43 44class ExpressionBuiltinType1(ExpressionBuiltinSingleArgBase): 45 kind = "EXPRESSION_BUILTIN_TYPE1" 46 47 def computeExpression(self, trace_collection): 48 value = self.subnode_value 49 50 type_shape = value.getTypeShape() 51 52 if type_shape is not None: 53 type_name = type_shape.getTypeName() 54 55 if type_name is not None and type_name in __builtins__: 56 result = ExpressionBuiltinRef( 57 builtin_name=type_name, source_ref=value.getSourceReference() 58 ) 59 60 result = wrapExpressionWithNodeSideEffects( 61 new_node=result, old_node=value 62 ) 63 64 return ( 65 result, 66 "new_builtin", 67 "Replaced predictable type lookup with builtin type '%s'." 68 % (type_name), 69 ) 70 71 if value.isCompileTimeConstant(): 72 # The above code is supposed to catch these in a better way. 73 value = value.getCompileTimeConstant() 74 75 type_name = value.__class__.__name__ 76 77 if type_name in builtin_names: 78 new_node = makeExpressionBuiltinRef( 79 builtin_name=type_name, 80 locals_scope=None, 81 source_ref=self.source_ref, 82 ) 83 else: 84 new_node = ExpressionBuiltinAnonymousRef( 85 builtin_name=type_name, source_ref=self.source_ref 86 ) 87 88 return ( 89 new_node, 90 "new_builtin", 91 "Replaced predictable type lookup with builtin type '%s'." 92 % (type_name), 93 ) 94 95 return self, None, None 96 97 @staticmethod 98 def getTypeShape(): 99 return tshape_type 100 101 def computeExpressionDrop(self, statement, trace_collection): 102 from .NodeMakingHelpers import ( 103 makeStatementExpressionOnlyReplacementNode, 104 ) 105 106 result = makeStatementExpressionOnlyReplacementNode( 107 expression=self.subnode_value, node=statement 108 ) 109 110 return ( 111 result, 112 "new_statements", 113 """\ 114Removed type taking for unused result.""", 115 ) 116 117 def mayRaiseException(self, exception_type): 118 return self.subnode_value.mayRaiseException(exception_type) 119 120 def mayHaveSideEffects(self): 121 return self.subnode_value.mayHaveSideEffects() 122 123 124class ExpressionBuiltinSuper2(ExpressionChildrenHavingBase): 125 """Two arguments form of super.""" 126 127 kind = "EXPRESSION_BUILTIN_SUPER2" 128 129 named_children = ("type_arg", "object_arg") 130 131 def __init__(self, type_arg, object_arg, source_ref): 132 ExpressionChildrenHavingBase.__init__( 133 self, 134 values={"type_arg": type_arg, "object_arg": object_arg}, 135 source_ref=source_ref, 136 ) 137 138 def computeExpression(self, trace_collection): 139 trace_collection.onExceptionRaiseExit(BaseException) 140 141 # TODO: Quite some cases should be possible to predict. 142 return self, None, None 143 144 145class ExpressionBuiltinSuper0(ExpressionChildrenHavingBase): 146 """Python3 form of super, arguments determined from cells and function arguments.""" 147 148 kind = "EXPRESSION_BUILTIN_SUPER0" 149 150 named_children = ("type_arg", "object_arg") 151 152 def __init__(self, type_arg, object_arg, source_ref): 153 ExpressionChildrenHavingBase.__init__( 154 self, 155 values={"type_arg": type_arg, "object_arg": object_arg}, 156 source_ref=source_ref, 157 ) 158 159 def computeExpression(self, trace_collection): 160 trace_collection.onExceptionRaiseExit(BaseException) 161 162 # TODO: Quite some cases should be possible to predict. 163 return self, None, None 164 165 166class ExpressionBuiltinIsinstance(ExpressionChildrenHavingBase): 167 kind = "EXPRESSION_BUILTIN_ISINSTANCE" 168 169 named_children = ("instance", "classes") 170 171 def __init__(self, instance, classes, source_ref): 172 ExpressionChildrenHavingBase.__init__( 173 self, 174 values={"instance": instance, "classes": classes}, 175 source_ref=source_ref, 176 ) 177 178 def computeExpression(self, trace_collection): 179 # TODO: Quite some cases should be possible to predict. 180 181 instance = self.subnode_instance 182 183 # TODO: Should be possible to query run time type instead, but we don't 184 # have that method yet. Later this will be essential. 185 if not instance.isCompileTimeConstant(): 186 trace_collection.onExceptionRaiseExit(BaseException) 187 188 return self, None, None 189 190 classes = self.subnode_classes 191 192 if not classes.isCompileTimeConstant(): 193 trace_collection.onExceptionRaiseExit(BaseException) 194 195 return self, None, None 196 197 # So if both are compile time constant, we are able to compute it. 198 return trace_collection.getCompileTimeComputationResult( 199 node=self, 200 computation=lambda: isinstance( 201 instance.getCompileTimeConstant(), classes.getCompileTimeConstant() 202 ), 203 description="Built-in call to 'isinstance' computed.", 204 ) 205 206 207class ExpressionBuiltinIssubclass(ExpressionChildrenHavingBase): 208 kind = "EXPRESSION_BUILTIN_ISSUBCLASS" 209 210 named_children = ("cls", "classes") 211 212 def __init__(self, cls, classes, source_ref): 213 ExpressionChildrenHavingBase.__init__( 214 self, 215 values={"cls": cls, "classes": classes}, 216 source_ref=source_ref, 217 ) 218 219 def computeExpression(self, trace_collection): 220 # TODO: Quite some cases should be possible to predict. 221 222 cls = self.subnode_cls 223 224 # TODO: Should be possible to query run time type instead, but we don't 225 # have that method yet. Later this will be essential. 226 if not cls.isCompileTimeConstant(): 227 trace_collection.onExceptionRaiseExit(BaseException) 228 229 return self, None, None 230 231 classes = self.subnode_classes 232 233 if not classes.isCompileTimeConstant(): 234 trace_collection.onExceptionRaiseExit(BaseException) 235 236 return self, None, None 237 238 # So if both are compile time constant, we are able to compute it. 239 return trace_collection.getCompileTimeComputationResult( 240 node=self, 241 computation=lambda: issubclass( 242 cls.getCompileTimeConstant(), classes.getCompileTimeConstant() 243 ), 244 description="Built-in call to 'issubclass' computed.", 245 ) 246 247 248class ExpressionTypeCheck(SideEffectsFromChildrenMixin, ExpressionChildHavingBase): 249 kind = "EXPRESSION_TYPE_CHECK" 250 251 named_child = "cls" 252 253 def __init__(self, cls, source_ref): 254 ExpressionChildHavingBase.__init__( 255 self, 256 value=cls, 257 source_ref=source_ref, 258 ) 259 260 @staticmethod 261 def getTypeShape(): 262 return tshape_bool 263 264 def computeExpression(self, trace_collection): 265 # TODO: Quite some cases should be possible to predict, but I am not aware of 266 # 100% true Python equivalent at this time. 267 return self, None, None 268