const ASTTypeVariable& ASTType::getTypeVariable() const { ASSERT(isGeneric()); if ( mKind == eArray ) { return mpArrayType->getTypeVariable(); } return *mpTypeVariable; }
static void reportType (tokenInfo *const token) { vStringUpper (token->string); if (vStringLength (token->string) > 0 && ! isGeneric (token) && (SelfReferences || strcmp (vStringValue ( token->string), vStringValue (token->className)) != 0) && ! stringListHas (ReferencedTypes, vStringValue (token->string))) { printf ("%s\n", vStringValue (token->string)); stringListAdd (ReferencedTypes, vStringNewCopy (token->string)); } }
void Tree::lookupAndSetTypeDefinitionInCurrentTree( Type* type, const NameBindings& scope, const Location& location) { auto definition = scope.lookupType(type->getName()); if (definition == nullptr) { Trace::error("Unknown type: " + type->getName(), location); } type->setDefinition(definition); auto classDefinition = definition->dynCast<ClassDefinition>(); if (classDefinition != nullptr && classDefinition == getCurrentClass()) { classDefinition->setRecursive(true); } if (type->isFunction()) { auto signature = type->getFunctionSignature(); lookupAndSetTypeDefinitionInCurrentTree(signature->getReturnType(), scope, location); for (auto argumentType: signature->getArguments()) { lookupAndSetTypeDefinitionInCurrentTree(argumentType, scope, location); } } if (type->hasGenericTypeParameters()) { // The type has generic type parameters. This means the type must refer // to a generic class. if (classDefinition == nullptr) { Trace::error("Only classes can take type parameters: " + type->getName(), location); } if (!classDefinition->isGeneric()) { Trace::error("Only generic classes can take type parameters: " + type->getName(), location); } for (auto typeParameter: type->getGenericTypeParameters()) { lookupAndSetTypeDefinitionInCurrentTree(typeParameter, scope, location); } } }
ClassDefinition* Tree::startClass( const Identifier& name, const GenericTypeParameterList& genericTypeParameters, const IdentifierList& parents, ClassDefinition::Properties& properties, const Location& location) { NameBindings* containingNameBindings = &globalNameBindings; auto containingClass = getCurrentClass(); if (containingClass != nullptr) { containingNameBindings = &(containingClass->getNameBindings()); } auto newClass = ClassDefinition::create(name, genericTypeParameters, parents, containingNameBindings, properties, location); if (containingClass != nullptr) { newClass->setIsImported(containingClass->isImported()); } if (!containingNameBindings->insertClass(name, newClass)) { Trace::error("Class already declared at the same scope: " + name, location); } if (!newClass->isGeneric()) { // For generic message classes, the empty copy constructor will be // generated when the concrete class is created from the generic one. if (newClass->needsCloneMethod()) { // The body of the copy constructor will be generated later by the // CloneGenerator, here we just generate an empty copy constructor. // The reason for generating an empty copy constructor at this stage // is that the copy constructor needs to be in the name bindings of // the new class before any other class can inherit from it. // Otherwise, the copy constructor will not be in the name bindings // of the derived class since name bindings are copied from the base // class to the derived class. newClass->generateEmptyCopyConstructor(); CloneGenerator::generateEmptyCloneMethod(newClass); } } openClasses.push_back(newClass); return newClass; }
Type* Tree::makeGenericTypeConcreteInCurrentTree( Type* type, const NameBindings& scope, const Location& location) { if (type->isFunction()) { makeSignatureTypesConcrete(type->getFunctionSignature(), scope, location); } auto typeDefinition = type->getDefinition(); assert(typeDefinition != nullptr); if (typeDefinition->isGenericTypeParameter()) { // Since the type is a generic type parameter, we must lookup the type // definition even though the type already has a definition. This is // because the generic type parameter definitions are cloned when a // concrete class is generated from a generic class, and the type needs // to refer to the cloned generic type parameter definition. lookupAndSetTypeDefinitionInCurrentTree(type, scope, location); return type->getConcreteTypeAssignedToGenericTypeParameter(); } if (type->hasGenericTypeParameters()) { // The type has type parameters. For example, the type could be like // this: 'Foo<T>' where T is a generic type parameter which we have to // map to a concrete type. Or, the type could be like this 'Foo<int>'. // In all cases we must make sure that the definition of the type is // the generated concrete class. assert(typeDefinition->getKind() == Definition::Class); auto classDef = typeDefinition->cast<ClassDefinition>(); if (classDef->isGeneric()) { // The class is still a generic, which means we must get the // generated concrete class. typeDefinition = getConcreteClassFromTypeParameterList(type, scope, classDef, location); type->setDefinition(typeDefinition); return type; } // The class is not generic so it is already the generated concrete // class. Do nothing. } return nullptr; }
/// \brief Test whether that is greater than this type bool ASTType::greater(const ASTType& that) const { if ( isNull() && (that.isObject() || that.isArray() || that.isString() || that.isGeneric()) ) { return true; } else if ( isObject() && that.isObject() ) { // check if 'that' is a extending or implemented this if ( !(mTypeArguments == that.mTypeArguments) ) { return false; } return getObjectClass().isBase(that.getObjectClass()) || getObjectClass().isImplementing(that.getObjectClass()); } else if ( isArray() && that.isArray() ) { return mpArrayType->equals(*that.mpArrayType) && mArrayDimension == that.mArrayDimension; } else if ( isGeneric() ) { if ( that.isObject() ) { return that.getObjectName() == UTEXT("system.Object"); // object is greater than a generic (its da uber type) } else if ( that.isGeneric() ) { return mObjectName == that.mObjectName; } } else if ( !isObject() && !that.isObject() ) { switch ( that.mKind ) { case eBoolean: return mKind == eBoolean; case eInt: return mKind == eInt; case eReal: return mKind == eInt || mKind == eReal; case eChar: return mKind == eChar; case eString: return mKind == eString || mKind == eInt || mKind == eReal || mKind == eBoolean || mKind == eChar; default: break; } } // no implicit primitive to basic or vs yet return false; }