/* st-inherit.cc: fill in class and interface environments with inherited members */ #include #include "AST.h" #include "MethodDecl.h" #include "StringSet.h" #include "compiler.h" #include "decls.h" #include "errors.h" // Returns true if dm is less accessible than mm bool isLessAccessible(Common::Modifiers dm, Common::Modifiers mm) { return (mm & Common::Public) && !(dm & Common::Public) || (mm & Common::Protected) && !(dm & (Common::Public | Common::Protected)) || !(mm & (Common::Public | Common::Protected)) && (dm & Common::Private); } // Returns true if dtype is a legal covariant replacement for mtype. bool isCovariantCompatible(TypeNode *dtype, TypeNode *mtype) { if (mtype->typeIdent(theVoidType) || dtype->typeIdent(theVoidType)) return mtype->typeIdent(dtype); else if (!mtype->isAssignableFromType(dtype)) return false; else if ((mtype->modifiers() & Common::Single) && // isAssignableFromType() ignores top-level !(dtype->modifiers() & Common::Single)) // singleness, so we must manually check it return false; else if (mtype->isPrimitive()) // for primitive types, covariance only allowed with return mtype->typeIdentNS(dtype); // respect to single qualification, a la JLS 3 else return true; } // Fake decl used to store methods defined in Object. ClassDecl *superintdecl = new ClassDecl(intern("ti_superinterface"), NULL, Common::Interface, NULL); // Returns true if newThrows is a "subset" of oldThrows (j8.4.4) static bool throwsSubset(TreeNode *newThrows, TreeNode *oldThrows) { foriter (newExc, newThrows->allTypes(), TreeNode::TypeIter) { bool found = false; Decl *newExcDecl = (*newExc)->decl(); // Unchecked exceptions can be declared anywhere. if (isSubClass(newExcDecl, RuntimeExceptionDecl) || isSubClass(newExcDecl, ErrorDecl)) continue; // Look for an exception in oldThrows that is a superclass of // newExc foriter (oldExc, oldThrows->allTypes(), TreeNode::TypeIter) // Is this right ? Or should it be isSubClass || isSuperInterface ? //if ((*oldExc)->isAssignableFromType((*newExc))) if (isSubClass(newExcDecl, (*oldExc)->decl())) { found = true; break; } if (!found) return false; } return true; } /* True if MEMBER would be hidden or overridden by a declaration in */ /* TO. */ static bool overriddenIn (Decl* member, Decl *to) { Environ *env = to->environ(); if (member->category() == Decl::Field) { Decl *current = env->lookupProper (member->name(), Decl::Field); // Only definitions in the destination environment override fields // If multiple definitions are inherited, a compile-time error // must be reported for any use (this is achieved by letting the // environment contain multiple copies of the field, which will // produce an ambiguous reference error in the name lookup) // But: multiple inheritances of the *same* field only count once return current != NULL && (current->container() == to || member == current); } else { foriter (d, env->lookupFirstProper (member->name(), Decl::Method), EnvironIter) { assert( d->category() == Decl::Method ); TypeNode *dtype = d->type(); TypeNode *mtype = member->type(); if (dtype->methodsConflict(mtype)) { // Note: member is overriden method, d is overriding method if (&*d == member) return true; // seeing the same thing twice bool isLocalDecl = d->container() == to; SourcePosn p = isLocalDecl ? d->source()->position() : to->source()->position(); Common::Modifiers dm = d->modifiers(); Common::Modifiers mm = member->modifiers(); // Note: if !isLocalDecl, then the method necessarily comes // from an interface (i.e. is abstract). If d is also abstract, // then all methods are inherited (j8.4.6.4). bool inheritAllAbstract = !isLocalDecl && (dm & Common::Abstract); // AK (PR798) -- Allow return type covariance. // Method{Decl,Signature,Type}Node keep track of two types: // returnType and declaredReturnType. The latter is the return // type declared by the user and is used for typechecking // purposes. The former is replaced below with what the return // type would be if covariance were not allowed. It is used by // widening to determine if narrowing (!) casts need to be // inserted, and by the backend, which is ignorant of covariance. // As a result, the generated code is pretty much exactly what // it would be if no covariance was used and a user manually // inserted casts. // Note that qualification inference must ensure that returnType // and declaredReturnType have the same qualifiers, in order for // subsequent typechecking to pass. if (!isCovariantCompatible(dtype->declaredReturnType(), mtype->declaredReturnType())) Error(p) << "overriding of " << member->errorName() << " incompatibly changes return type" << endl; else { // Ensure that the actual return type of the overriding method // is the same as the overridden one. d->source()->returnType(mtype->returnType()); dtype->returnType(mtype->returnType()); } if (!dtype->paramTypes()->singleArgsIdent(mtype->paramTypes())) Error(p) << "overriding of " << member->errorName() << " changes 'single' argument declarations" << endl; #ifndef SGLOBAL_INFERENCE if ((dm & Common::Sglobal) && !(mm & Common::Sglobal)) Error(p) << "overriding of " << member->errorName() << " adds 'single'" << endl; #endif if ((dm & Common::Static) != (mm & Common::Static)) Error(p) << "overriding of " << member->errorName() << " adds/removes 'static'" << endl; // make sure d was a legal override/hide of member if (mm & Common::Final) Error(p) << "cannot override final " << member->errorName() << endl; if (isLessAccessible(dm, mm)) Error(p) << "overriding of " << member->errorName() << " must provide at least as much access" << endl; if (!inheritAllAbstract && !throwsSubset(d->type()->throws(), member->type()->throws())) Error(p) << d->errorName() << " throws more exceptions than overriden " << member->errorName() << endl; // update overriding/hiding information for declarations of 'to' if (member->container()->category() == Decl::Interface) { // Cannot use isLocalDecl to determine if overridden method // should be added to d->implements(). d could be inherited // from a superclass that does not implement member's // interface, but the current class implements that interface, // resulting in d implementing member for the current class. assert(member->category() == Decl::Method); bool registered = false; const MethodSet &implements = d->implements(); for (MethodSet::const_iterator interface = implements.begin(); interface != implements.end(); ++interface) if (member == *interface) registered = true; if (!registered) { member->overriders((MethodDecl *)&*d); d->implements((MethodDecl *) member); } } else if (isLocalDecl) { member->overriders((MethodDecl *)&*d); d->overrides(member); } return !inheritAllAbstract; } } return false; } } /* Given ClassDecls TO and FROM, add to *TO->environ() the members */ /* that TO inherits from FROM. */ void fillInInheritedMembers (Decl* to, Decl* from, int categories) { // make sure 'from' is filled in if (from->source() && !from->source()->absent()) from->source()->resolveInheritance(); foriter (member, from->environ()->allProperDecls(), EnvironIter) if ((member->category() & categories) != 0 && ((member->modifiers() & Common::Private) == 0) && ! overriddenIn (&*member, to)) to->environ()->add (&*member); } /* Given interface ClassDecl TO and FROM, add to *TO->environ() the */ /* members of Object that TO implicitly defines. */ void fillInImplicitMembers (Decl* to) { Decl *from = superintdecl; foriter (member, from->environ()->allProperDecls(), EnvironIter) // Override check makes sure signature of method not changed incompatibly. if (! overriddenIn (&*member, to)) { // Add method into environment. MethodDecl *tmp = new MethodDecl(member->name(), member->type(), member->category(), (ClassDecl*) to, member->modifiers(), member->source()->deepClone()); to->environ()->add (tmp); // Add method into InterfaceDeclNode. TreeNode *c = to->source(); TreeNode *m = tmp->source(); m->simpName()->decl(tmp); llist *lst = cons(m); lst = appendTreeList((TreeListNode *) c->members(), lst); c->members(new TreeListNode(lst, c->members()->position())); } } /* Static analysis, phase 2b: fill in class and interface environments with inherited members */ void TreeNode::resolveInheritance() { undefined("resolveInheritance"); } void CompileUnitNode::resolveInheritance() { foriter (type, types()->allChildren(), ChildIter) (*type)->resolveInheritance(); } void TemplateDeclNode::resolveInheritance() { } static const StringSet abstractMethods(TreeNode *classNode) { Environ *classEnv = classNode->decl()->environ(); StringSet methods; // check for abstract methods foriter (member, classEnv->allProperDecls(), EnvironIter) if ((member->category() & Decl::Method) && (member->modifiers() & Common::Abstract)) methods.insert(member->errorName()); return methods; } void ClassDeclNode::resolveInheritance() { Decl* me = decl(); int categories; if (me->visits < 1 || me->visits > 2) return; else if (me->visits == 1) { // Can only fill in fields now. And need to fill in fields so that template types // as part of method, constructor, and field signatures can be resolved. categories = Decl::Field; } else { // visits temporarily set to 3 to prevent infinite loops with circularly // dependent types. me->visits = 3; // Check if supertypes are ready for filling in methods. bool ready = true; if (!(flags() & Immutable)) { me->superClass()->source()->resolveInheritance(); ready &= (me->superClass()->visits == 3); foriter (interface, elements(me->interfaces()), ListIterator) { (*interface)->source()->resolveInheritance(); ready &= ((*interface)->visits == 3); } } if (ready) { // OK to fill in fields again, since they get checked to see if they are already // there, and never produce error messages. categories = Decl::Field | Decl::Method; } else { // visits reset to 2. me->visits = 2; // Only OK to fill in fields. categories = Decl::Field; } } // Check me->visits so that error messages only get printed once. if (!(flags() & Immutable)) { fillInInheritedMembers(me, me->superClass(), categories); foriter (interface, elements(me->interfaces()), ListIterator) fillInInheritedMembers(me, *interface, categories); if (me->visits == 3 && me->superClass()->modifiers() & Final) error() << "final or immutable class " << me->superClass()->errorName() << " cannot be extended" << endl; } if (me->visits == 3 && (flags() & (Final | Abstract)) == (Final | Abstract)) error() << "a class cannot be final and abstract" << endl; if (me->visits == 3 && !(flags() & Abstract)) { const StringSet methods = abstractMethods(this); if (!methods.empty()) { error() << me->errorName() << " has abstract methods: must be declared abstract" << endl; for (StringSet::const_iterator method = methods.begin(); method != methods.end(); ++method) message() << *method << " is abstract" << endl; } } } void InterfaceDeclNode::resolveInheritance() { Decl* me = decl(); int categories; if (me->visits < 1 || me->visits > 2) return; else if (me->visits == 1) { // Can only fill in fields now. And need to fill in fields so that template types // as part of method, constructor, and field signatures can be resolved. categories = Decl::Field; } else { // visits temporarily set to 3 to prevent infinite loops with circularly // dependent types. me->visits = 3; // Check if supertypes are ready for filling in methods. bool ready = true; foriter (interface, elements(me->interfaces()), ListIterator) { (*interface)->source()->resolveInheritance(); ready &= ((*interface)->visits == 3); } if (me->interfaces() == NULL) // Interfaces with no supertypes implicitly define Object's methods. ready &= (ObjectDecl->visits >= 2); if (ready) { // OK to fill in fields again, since they get checked to see if they are already // there, and never produce error messages. categories = Decl::Field | Decl::Method; } else { // visits reset to 2. me->visits = 2; // Only OK to fill in fields. categories = Decl::Field; } } foriter (interface, elements (me->interfaces()), ListIterator) fillInInheritedMembers(me, *interface, categories); if (me->interfaces() == NULL) // Interfaces with no supertypes implicitly define Object's methods. fillInImplicitMembers(me); }