#include "AST.h" #include "TypeContext.h" #include "code-util.h" #include "compiler.h" #include "decls.h" #include "errors.h" #include "tclimits.h" #include "utils.h" // Maximum depth of inheritance tree. int maxInheritanceDepth = 17; // Is the class ready for type lookups? bool ClassDecl::isTypeReady() const { return mark >= 2; } static bool hiddenIn (Decl* member, Decl *to) { Environ *env = to->environ(false); if (member->category() == Decl::Class || member->category() == Decl::Interface) { Decl *current = env->lookupProper (member->declaredName(), Decl::Class | Decl::Interface); // 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->source()->enclosingType() == to->source() || member == current); } else return false; } /* Given ClassDecls TO and FROM, add to *TO->environ() the members */ /* that TO inherits from FROM. */ void fillInInheritedTypes (Decl* to, Decl* from) { if (!from->hasSource()) return; // This is for error cases like extending a primitive. foriter (member, from->environ(false)->allProperDecls(), EnvironIter) if ((member->category() == Decl::Class || member->category() == Decl::Interface) && ((member->modifiers() & Common::Private) == 0) && ! hiddenIn (&*member, to)) to->environ(false)->add ((*member).declaredName(), &*member); } TreeNode *TreeNode::buildTypeEnv(TypeContext *ctx) { for (int i = 0; i < arity(); i++) child(i, child(i)->buildTypeEnv(ctx)); return this; } TreeNode *CompileUnitNode::buildTypeEnv(TypeContext *ctx) { bool postponed = false; TypeContext subCtx(*ctx, postponed); subCtx.package = thePackage; subCtx.fileEnv = subCtx.typeEnv = environ(); for (int i = 0; i < types()->arity(); i++) { types()->child(i)->buildTypeEnv(&subCtx); if (postponed) { ctx->postponed = true; postponed = false; } } return this; } TreeNode *ClassDeclNode::buildTypeEnv(TypeContext *ctx) { if (ctx->depth >= maxInheritanceDepth) { error() << "inheritance depth exceeds maximum of " << maxInheritanceDepth << endl; message() << " (use \"-inheritance-depth \" to increase the maximum)" << endl; superClass(TreeNode::omitted); llist *lst = NULL; interfaces(new TypeListNode(lst, interfaces()->position())); } Decl *me = decl(); if (me->mark == 1) { error() << me->errorName() << " in circular definition" << endl; me->mark = 2; // No return so that all types in circularity are reported. } else if (me->mark >= 2) return this; else me->mark = 1; bool postponed = false; TypeContext subCtx(*ctx, postponed); subCtx.package = me->container(); subCtx.cclass = decl()->asType(); subCtx.depth += 1; // package->environ() does not work (due to multiple classes defined in the // same file; also does not work for templates. subCtx.fileEnv = parent()->parent()->environ(); // Super class and interfaces must be resolved in enclosing type env. subCtx.typeEnv = enclosingType() ? enclosingType()->decl()->environ(false) : subCtx.fileEnv; if (!superClass()->absent()) { superClass(superClass()->buildTypeEnv(&subCtx)); if (!postponed) fillInInheritedTypes(me, superClass()->decl()); } for (int i = 0; i < interfaces()->arity(); i++) { interfaces()->child(i, (TypeNode *) interfaces()->child(i)->buildTypeEnv(&subCtx)); if (!postponed) fillInInheritedTypes(me, interfaces()->child(i)->decl()); } ctx->postponed |= postponed; me->mark = postponed ? 0 : 2; return this; } TreeNode *TemplateDeclNode::buildTypeEnv(TypeContext *ctx) { return this; } TreeNode *InterfaceDeclNode::buildTypeEnv(TypeContext *ctx) { if (ctx->depth >= maxInheritanceDepth) { error() << "inheritance depth exceeds maximum of " << maxInheritanceDepth << endl; message() << " (use \"-inheritance-depth \" to increase the maximum)" << endl; llist *lst = NULL; interfaces(new TypeListNode(lst, interfaces()->position())); } Decl *me = decl(); if (me->mark == 1) { error() << me->errorName() << " in circular definition" << endl; me->mark = 2; // No return so that all types in circularity are reported. } else if (me->mark >= 2) return this; else me->mark = 1; bool postponed = false; TypeContext subCtx(*ctx, postponed); subCtx.package = me->container(); subCtx.cclass = decl()->asType(); subCtx.depth += 1; // package->environ() does not work (due to multiple classes defined in the // same file; also does not work for templates. subCtx.fileEnv = parent()->parent()->environ(); // Super interfaces must be resolved in enclosing type env. subCtx.typeEnv = enclosingType() ? enclosingType()->decl()->environ(false) : subCtx.fileEnv; for (int i = 0; i < interfaces()->arity(); i++) { interfaces()->child(i, (TypeNode *) interfaces()->child(i)->buildTypeEnv(&subCtx)); if (!postponed) fillInInheritedTypes(me, interfaces()->child(i)->decl()); } ctx->postponed |= postponed; me->mark = postponed ? 0 : 2; return this; } TreeNode *TypeNameNode::buildTypeEnv(TypeContext *ctx) { name(name()->buildTypeEnv(ctx)); return this; } TreeNode *TemplateInstanceTypeNode::buildTypeEnv(TypeContext *ctx) { if (!decl()) { ctx->postponed = true; return resolveTypes(ctx); } else { if (!ctx->noRecurse) decl()->source()->buildTypeEnv(ctx); bool postponed = false; TypeContext subCtx(*ctx, postponed); // Allow parameterizations that depend only on a raw type being currently // resolved. subCtx.noRecurse = true; for (int i = 0; i < args()->arity(); i++) { args()->child(i, args()->child(i)->buildTypeEnv(&subCtx)); } ctx->postponed |= postponed; return this; } } TreeNode *TemplateNameNode::buildTypeEnv(TypeContext *ctx) { ttype()->buildTypeEnv(ctx); return this; } TreeNode *ExprNode::buildTypeEnv(TypeContext *ctx) { TypeContext subCtx(*ctx); subCtx.resolveAsType = false; subCtx.noRecurse = false; return TreeNode::buildTypeEnv(&subCtx); } TreeNode *NameNode::buildTypeEnv(TypeContext *ctx) { if (decl() == UnknownClassDecl) return this; if (!qualifier()->absent()) { TypeContext subCtx(*ctx); // Only innermost name can be object or raw type. subCtx.resolveAsType = true; subCtx.noRecurse = false; qualifier(qualifier()->buildTypeEnv(&subCtx)); if (!qualifier()->decl()) { ctx->postponed = true; return this; } } if (!ctx->resolveAsType) return this; int categories = Decl::Class | Decl::Interface | Decl::TypePseudonym; if (qualifier()->absent() || qualifier()->decl()->category() == Decl::Package) categories |= Decl::Package; bool postponed = false; TreeNode *resolved = resolveAName(this, *ctx->typeEnv, NULL, None, ctx->package, postponed, categories); ctx->postponed |= postponed; if (postponed) return this; Decl *d = resolved->decl(); if ((d->category() & (Decl::Package | Decl::Class | Decl::Interface | Decl::TypePseudonym)) == 0 || (d->category() != Decl::Package && isTemplateDeclNode(d->source()->parent()))) { error() << d->errorName() << " cannot appear in an " << "EXTENDS or IMPLEMENTS clause" << endl; decl(UnknownClassDecl); return this; } if (decl()->category() != Decl::Package && !ctx->noRecurse) d->source()->buildTypeEnv(ctx); if (decl()->category() == Decl::TypePseudonym) { assert(resolved->isTypeNode()); return resolved->name(); } else return this; }