def visit_newtype_expr(self, node: NewTypeExpr) -> NewTypeExpr: res = NewTypeExpr(node.name, node.old_type, line=node.line, column=node.column) res.info = node.info return res
def process_newtype_declaration(self, s: AssignmentStmt) -> None: """Check if s declares a NewType; if yes, store it in symbol table.""" # Extract and check all information from newtype declaration name, call = self.analyze_newtype_declaration(s) if name is None or call is None: return old_type = self.check_newtype_args(name, call, s) call.analyzed = NewTypeExpr(name, old_type, line=call.line, column=call.column) if old_type is None: return # Create the corresponding class definition if the aliased type is subtypeable if isinstance(old_type, TupleType): newtype_class_info = self.build_newtype_typeinfo( name, old_type, old_type.partial_fallback) newtype_class_info.tuple_type = old_type elif isinstance(old_type, Instance): if old_type.type.is_protocol: self.fail("NewType cannot be used with protocol classes", s) newtype_class_info = self.build_newtype_typeinfo( name, old_type, old_type) else: message = "Argument 2 to NewType(...) must be subclassable (got {})" self.fail(message.format(self.msg.format(old_type)), s) return check_for_explicit_any(old_type, self.options, self.api.is_typeshed_stub_file, self.msg, context=s) if self.options.disallow_any_unimported and has_any_from_unimported_type( old_type): self.msg.unimported_type_becomes_any("Argument 2 to NewType(...)", old_type, s) # If so, add it to the symbol table. node = self.api.lookup(name, s) if node is None: self.fail("Could not find {} in current namespace".format(name), s) return # TODO: why does NewType work in local scopes despite always being of kind GDEF? node.kind = GDEF call.analyzed.info = node.node = newtype_class_info
def process_newtype_declaration(self, s: AssignmentStmt) -> bool: """Check if s declares a NewType; if yes, store it in symbol table. Return True if it's a NewType declaration. The current target may be deferred as a side effect if the base type is not ready, even if the return value is True. The logic in this function mostly copies the logic for visit_class_def() with a single (non-Generic) base. """ name, call = self.analyze_newtype_declaration(s) if name is None or call is None: return False # OK, now we know this is a NewType. But the base type may be not ready yet, # add placeholder as we do for ClassDef. fullname = self.api.qualified_name(name) if (not call.analyzed or isinstance(call.analyzed, NewTypeExpr) and not call.analyzed.info): # Start from labeling this as a future class, as we do for normal ClassDefs. placeholder = PlaceholderNode(fullname, s, s.line, becomes_typeinfo=True) self.api.add_symbol(name, placeholder, s, can_defer=False) old_type, should_defer = self.check_newtype_args(name, call, s) if not call.analyzed: call.analyzed = NewTypeExpr(name, old_type, line=call.line, column=call.column) if old_type is None: if should_defer: # Base type is not ready. self.api.defer() return True # Create the corresponding class definition if the aliased type is subtypeable if isinstance(old_type, TupleType): newtype_class_info = self.build_newtype_typeinfo( name, old_type, old_type.partial_fallback) newtype_class_info.tuple_type = old_type elif isinstance(old_type, Instance): if old_type.type.is_protocol: self.fail("NewType cannot be used with protocol classes", s) newtype_class_info = self.build_newtype_typeinfo( name, old_type, old_type) else: if old_type is not None: message = "Argument 2 to NewType(...) must be subclassable (got {})" self.fail(message.format(self.msg.format(old_type)), s) # Otherwise the error was already reported. old_type = AnyType(TypeOfAny.from_error) object_type = self.api.named_type('__builtins__.object') newtype_class_info = self.build_newtype_typeinfo( name, old_type, object_type) newtype_class_info.fallback_to_any = True check_for_explicit_any(old_type, self.options, self.api.is_typeshed_stub_file, self.msg, context=s) if self.options.disallow_any_unimported and has_any_from_unimported_type( old_type): self.msg.unimported_type_becomes_any("Argument 2 to NewType(...)", old_type, s) # If so, add it to the symbol table. assert isinstance(call.analyzed, NewTypeExpr) # As we do for normal classes, create the TypeInfo only once, then just # update base classes on next iterations (to get rid of placeholders there). if not call.analyzed.info: call.analyzed.info = newtype_class_info else: call.analyzed.info.bases = newtype_class_info.bases self.api.add_symbol(name, call.analyzed.info, s) newtype_class_info.line = s.line return True
def visit_newtype_expr(self, node: NewTypeExpr) -> NewTypeExpr: return NewTypeExpr(node.info)