/* scope.cc: Definitions for member functions that manage name binding */ #include #include "AST.h" #include "ClassContext.h" #include "FieldDecl.h" #include "MethodDecl.h" #include "TypeContext.h" #include "compiler.h" #include "decls.h" #include "errors.h" #include "code-util.h" /* Utilities */ template class llist; llist *addToFront(TreeNode *, TreeListNode *); extern NameNode *buildName(const char *fullname, SourcePosn pos); extern bool isLessAccessible(Common::Modifiers, Common::Modifiers); // Is the class ready for field lookups? bool ClassDecl::isFieldReady() const { return visits >= 1; } // Is the class ready for method lookups? bool ClassDecl::isMethodReady() const { return visits >= 3; } // Build the name for the field corresponding to the enclosing instance. NameNode *buildOuterNameNode(TreeNode *qualifier, SourcePosn posn) { return new NameNode(qualifier, intern("nc_5outer"), NULL, posn); } // Build the inner class field corresponding to the enclosing instance. static FieldDeclNode *buildOuterFieldNode(TypeDeclNode *cclass, SourcePosn posn) { NameNode *name = buildOuterNameNode(TreeNode::omitted, posn); // Package resolution has already occurred. TypeNode *tn = cclass->enclosingType()->decl()->asType()->deepClone(); return new FieldDeclNode(tn, name, (Common::Modifiers) (TreeNode::Final | TreeNode::Private | TreeNode::CompilerGenerated), TreeNode::omitted, posn); } // Build the name for the parameter used to pass the enclosing instance of // an inner class to its constructor. static NameNode *buildOuterParamNameNode(SourcePosn posn) { return buildName("nc_5outer_", posn); } // Build a method parameter used to pass the enclosing instance of an // inner class its to constructor. static ParameterNode *buildOuterParameterNode(TypeDeclNode *cclass, SourcePosn posn) { NameNode *id = buildOuterParamNameNode(posn); // Package resolution has already occurred. TypeNode *type = cclass->enclosingType()->decl()->asType()->deepClone(); return new ParameterNode(true, type, id, posn); } // Build an assignment statement between the given field and parameter. static StatementNode *buildAssignmentNode(TreeNode *id0, TreeNode *id1, SourcePosn posn) { ThisNode *tn = new ThisNode(TreeNode::omitted, NULL, TreeNode::None, posn); ObjectNode *on = new ObjectNode(id1, posn); ObjectFieldAccessNode *ofan = new ObjectFieldAccessNode(tn, id0, posn); AssignNode *an = new AssignNode(ofan, on, posn); return new ExpressionStmtNode(an, posn); } // Build a statement to initialize the enclosing instance of an inner class. static StatementNode *buildOuterAssignmentNode(TypeDeclNode *cclass, SourcePosn posn) { NameNode *id0 = buildOuterNameNode(TreeNode::omitted, posn); NameNode *id1 = buildOuterParamNameNode(posn); return buildAssignmentNode(id0, id1, posn); } // Build a parameter name for the given field name. NameNode *paramNameNode(TreeNode *name, SourcePosn posn) { string pn = "nc_" + int2string(name->ident()->length() + 1) + *name->ident() + "_"; return buildName(pn.c_str(), posn); } // Rewrite constructor parameters for local classes. llist *rewriteParamsList(TreeListNode *tln, TreeNode *lst) { llist *tmp = appendTreeList(tln, NULL); llist *tmp2 = NULL; for (int i = lst->arity()-1; i >= 0; i--) { tmp2 = cons(static_cast(new ParameterNode(true, lst->child(i)->dtype()->deepClone(), paramNameNode(lst->child(i)->simpName(), tln->position()), tln->position())), tmp2); } return extend(tmp2, tmp); } // Rewrite initializer for local classes. TreeNode *rewriteInitializer(TreeNode *init, TreeNode *lst, SourcePosn posn) { llist *tmp = NULL; for (int i = lst->arity()-1; i >= 0; i--) { tmp = cons(static_cast(buildAssignmentNode(lst->child(i)->simpName()->deepClone(), paramNameNode(lst->child(i)->simpName(), posn), posn)), tmp); } if (init != NULL && !init->absent()) tmp = cons(init, tmp); return new BlockNode(tmp, NULL, posn); } // Check if the decl in a type exists. static bool declAvailable(TypeNode *tn) { if (tn->isArrayType()) // it may not be legal to build array decls yet return declAvailable(tn->elementType()); else if (isTypeNameNode(tn) || isTemplateInstanceTypeNode(tn)) return tn->decl(); else return true; } // Check if all the types in a method/constructor's parameter list and return // type are available. static bool allTypesAvailable(TreeNode *tn) { assert(isMethodDeclNode(tn) || isMethodSignatureNode(tn) || isConstructorDeclNode(tn)); for (int i = 0; i < tn->params()->arity(); i++) { if (!declAvailable(tn->params()->child(i)->dtype())) return false; } for (int i = 0; i < tn->throws()->arity(); i++) { if (!declAvailable(tn->throws()->child(i))) return false; } if (!isConstructorDeclNode(tn) && (!declAvailable(tn->returnType()) || !declAvailable(tn->declaredReturnType()))) return false; return true; } /* A default constructor for the class declared by ClassDeclNode CL, */ /* as it would be produced by the parser, had it been written */ /* explicitly: public polyshared Foo() { super(); } */ static TreeNode* defaultConstructor (TreeNode* cl) { unsigned flags = cl->flags() & Common::Public | Common::CompilerGenerated; /* PR512: default constructors are shared if (!cl->decl()->asType()->isImmutable()) flags |= Common::PolysharedQ; */ return new ConstructorDeclNode ((Common::Modifiers) flags, NULL, new NameNode(TreeNode::omitted, cl->simpName()->ident(), NULL, cl->position()), NULL, new SuperConstructorCallNode(Common::CompilerGenerated, TreeNode::omitted, NULL, NULL, cl->position()), new BlockNode(NULL, NULL, cl->position()), TreeNode::omitted, cl->position()); } /* the implicit .class field added to each non-immutable Class and Interface * as it would be produced by the parser, had it been written * explicitly: public final static [shared] Class class = [thisClass].class; * the initializer is to prevent default initialization clobbering it to null * after the native code in the static constructor initializes it. */ static TreeNode * classField (TreeNode* cl) { unsigned flags = Common::Public | Common::Final | Common::Static | Common::CompilerGenerated; TypeNameNode *tnn = new TypeNameNode( buildName("java.lang.Class", cl->position()), cl->position()); /* need to resolve the TypeNameNode */ TreeNode *p = cl; while (!isCompileUnitNode(p)) p = p->parent(); bool postponed = false; TreeNode::TypeContext ctx(postponed); ctx.package = p->package()->absent() ? unnamedPackage : p->package()->decl(); ctx.cclass = cl->decl()->asType(); ctx.fileEnv = ctx.typeEnv = p->environ(); assert(!postponed); tnn->resolveTypes(&ctx); FieldDeclNode *fielddeclnode = new FieldDeclNode(tnn, buildName("class", cl->position()), (Common::Modifiers) flags, TreeNode::omitted, cl->position()); fielddeclnode->initExpr(new TypeFieldAccessNode(cl->decl()->asType(), buildName("class", cl->position()), cl->position())); return fielddeclnode; } /* Name resolution, pass 1: for ClassDeclNodes and */ /* InterfaceDeclNodes: modify *THIS to create Decls for all its */ /* members */ /* PACKAGE is the package environment containing all these nodes. */ void TreeNode::resolveClass(ClassContext *ctx) { foriter (p, allChildren(), ChildIter) (*p)->resolveClass(ctx); } void CompileUnitNode::resolveClass(ClassContext *ctx) { ClassContext subCtx(*ctx); subCtx.package = thePackage; subCtx.fileEnv = environ(); types()->resolveClass(&subCtx); } void TemplateDeclNode::resolveClass( ClassContext *ctx ) { } void ClassDeclNode::resolveClass(ClassContext *ctx) { ClassDecl &me = *decl(); if (!me.isTypeReady()) { ctx->postponed = true; return; } else if (me.visits > 1) return; bool postponed = false; ClassContext subCtx(*ctx, postponed); subCtx.cclass = &me; if (me.visits < 1) { me.visits = 1; assert(!(flags() & Interface)); // An interface's member types are implicitly public and static. if (enclosingType() && (enclosingType()->flags() & Interface)) flags((Modifiers)(flags() | Static | Public)); // The strictfp modifier propogates to member classes. if (enclosingType() && (enclosingType()->flags() & Strictfp)) flags((Modifiers)(flags() | Strictfp)); if (enclosingType() && enclosingType()->enclosingType() && !(enclosingType()->flags() & Static) && (flags() & Static)) error() << "inner classes cannot have static nested classes" << endl; if (enclosingType() && (flags() & Immutable) && !(flags() & Static)) error() << "immutable nested classes must be static" << endl; if (flags() & Immutable) { if (!superClass()->absent()) error() << "immutable classes cannot extend classes" << endl; if (interfaces()->arity() > 0) error() << "immutable classes cannot implement interfaces" << endl; flags((Modifiers)(flags() | Final)); } else { ClassDecl *super = superClass()->absent() ? ObjectDecl : static_cast(superClass()->decl()); if (super->category() != Decl::Class) { // For anonymous classes that implement an interface. if (flags() & AnonymousClass) { llist *tmp = cons(super->asType()); interfaces(new TypeListNode(tmp, superClass()->position())); } else error() << "class " << *decl()->declaredName() << " cannot EXTEND interface " << *super->name() << endl; super = ObjectDecl; } superClass(super->asType()); me.superClass(super); me.interfaces(NULL); foriter (interface, interfaces()->allChildren(), ChildIter) { Decl *intf = (*interface)->decl(); if (intf->category() != Decl::Interface) error() << "class " << *decl()->declaredName() << " cannot IMPLEMENT class " << *intf->name() << endl; else me.interfaces(cons(intf, me.interfaces())); } } /* init hidden .class field: member 1 reserved for this purpose in the parser */ if (decl()->fullName() != "ti.internal.tiUnknown") members()->child(1, classField(this)); // Add field for enclosing instance if necessary. if (hasEnclosingInstance()) { llist *lst = appendTreeList(members(), cons(static_cast(buildOuterFieldNode(this, position())))); members(new TreeListNode(lst, members()->position())); } } else { // All members have undergone class resolution, but methods might have // been postponed due to unavailable types. subCtx.methodsOnly = true; } if (flags() & AnonymousClass) { // Defer class resolution of anonymous constructor. for (int i = 0; i < members()->arity(); i++) { if (!(isConstructorDeclNode(members()->child(i)) && (members()->child(i)->flags() & CompilerGenerated))) members()->child(i)->resolveClass(&subCtx); } } else { members()->resolveClass(&subCtx); bool needsDefault = true; if (flags() & Immutable) { // check if there is a zero-argument constructor EnvironIter iter = me.environ()->lookupFirstProper(me.name(), Decl::Constructor); foriter(d, iter, EnvironIter) { TreeNode *tn = d->source(); if (tn->params()->arity() == 0) { needsDefault = false; break; } } } else { needsDefault = (me.environ()->lookupProper(me.name(), Decl::Constructor) == NULL); } if (needsDefault) { /* member 2 reserved for this purpose in the parser */ members()->child(2, defaultConstructor(this)); members()->child(2)->resolveClass(&subCtx); } } ctx->postponed |= postponed; me.visits = postponed ? 1 : 2; if (&me == ObjectDecl && !postponed) { // Compute methods that interfaces implicitly define and store them in // a fake decl. Interfaces will fill these in in inheritance resolution. extern ClassDecl *superintdecl; superintdecl->environ(new Environ()); superintdecl->visits = 3; foriter (member, me.environ()->allProperDecls(), EnvironIter) if (((member->category() & Decl::Method) != 0) && ((member->modifiers() & Common::Static) == 0) && ((member->modifiers() & Common::Public) != 0)) { Modifiers mods = (Modifiers) ((member->modifiers() | Abstract | CompilerGenerated) & ~(Final | Native)); llist *newParams = appendTreeList(member->source()->params()->deepClone(), NULL); llist *newThrows = NULL; TypeNode *newReturn = member->source()->returnType()->deepClone(); TreeNode *newName = member->source()->simpName()->deepClone(); SourcePosn newPosn = member->source()->position(); for (int i = member->source()->throws()->arity() - 1; i >= 0; i--) newThrows = cons(member->source()->throws()->child(i), newThrows); MethodSignatureNode *mn = new MethodSignatureNode(mods, newParams, newReturn, newReturn, newName, newThrows, newPosn); MethodDecl *m = new MethodDecl(member->name(), member->type(), member->category(), (ClassDecl*) member->container(), mods, mn); mn->simpName()->decl(m); superintdecl->environ()->add (m); } } } void FieldDeclNode::resolveClass(ClassContext *ctx) { if (ctx->methodsOnly) return; if (ctx->cclass->source()->enclosingType() && (!(ctx->cclass->modifiers() & Static) || (ctx->cclass->modifiers() & LocalClass)) && (flags() & Static) && !(flags() & Final)) error() << "inner classes cannot have non-final static fields" << endl; if (!ctx->cclass->superClass() && !(flags() & Static)) // immutable class flags((Common::Modifiers)(flags() | Final)); if ((flags() & Final) && (flags() & Volatile)) error() << "field " << *simpName()->ident() << " cannot be final and volatile" << endl; Decl* d; dtype()->resolveClass(ctx); d = ctx->cclass->environ()->lookupProper(simpName()->ident(), Decl::Field); if (d != NULL) { error() << "redeclaration of " << d->errorName() << endl; simpName()->decl(d); return; } d = new FieldDecl(simpName()->ident(), dtype(), ctx->cclass, flags(), this); ctx->cclass->environ()->add(d); simpName()->decl(d); } void MethodDeclNode::resolveClass(ClassContext *ctx) { if (ctx->methodsOnly) { MethodNode::resolveClass(ctx); return; } if (ctx->cclass->source()->enclosingType() && (!(ctx->cclass->modifiers() & Static) || (ctx->cclass->modifiers() & LocalClass)) && (flags() & Static)) error() << "inner classes cannot have static methods" << endl; // methods in immutable classes and private methods are final if ((flags() & Private) || !ctx->cclass->superClass()) flags((Modifiers)(flags() | Final)); if (body()->absent()) { if (flags() & Abstract) { if (flags() & (Private | Static | Final | Synchronized | Native | Inline)) error() << "can't use private, static, final, synchronized, inline or native with abstract" << endl; } else if (!(flags() & Native)) error() << "abstract or native required on methods without a body" << endl; } else if (flags() & (Abstract | Native)) error() << "an abstract or native method cannot have a body" << endl; MethodNode::resolveClass(ctx); } void MethodNode::resolveClass(ClassContext *ctx) { if (!allTypesAvailable(this)) { ctx->postponed = true; return; } else if (simpName()->decl()) return; TypeNode *mType = typeFromMethodDeclNode(this); if (flags() & Static) { Modifiers forbidden = (Modifiers) (flags() & (Local | NonsharedQ | PolysharedQ)); if (forbidden) error() << "a static method cannot be " << stringifyModifiers( forbidden ) << endl; } // Check that this method is legal foriter (dd, ctx->cclass->environ()->lookupFirstProper(simpName()->ident(), Decl::Method), EnvironIter) if (mType->methodsConflict(dd->type())) error() << "illegal overloading of " << dd->errorName() << endl; Decl* d = new MethodDecl(simpName()->ident(), mType, Decl::Method, ctx->cclass, flags(), this); ctx->cclass->environ()->add(d); simpName()->decl(d); } void ConstructorDeclNode::resolveClass(ClassContext *ctx) { if (!allTypesAvailable(this)) { ctx->postponed = true; return; } else if (simpName()->decl()) return; flags( (Modifiers) (flags() | Local) ); ClassDeclNode *outer = (ClassDeclNode *) ctx->cclass->source(); if ((outer->flags() & AnonymousClass) && !(flags() & CompilerGenerated)) { // Anonymous classes can't have constructors. error() << "constructor declarations not allowed for anonymous classes" << endl; } if ((outer->flags() & LocalClass) && !outer->finalVars()->absent()) { // This is local class. Add final locals and parameters as args. llist *lst = rewriteParamsList(params(), outer->finalVars()); params(new TreeListNode(lst, params()->position())); } if (outer->enclosingType() && outer->hasEnclosingInstance()) { // Add implicit $outer argument. llist *lst = addToFront(buildOuterParameterNode(outer, params()->position()), params()); params(new TreeListNode(lst, params()->position())); // Null check of $_outer added in lower.cc. // Add assignment to $outer. This gets lowered in lower.cc // so that it executes before instance initializers. initEncloser(buildOuterAssignmentNode(outer, position())); } if ((outer->flags() & LocalClass) && !outer->finalVars()->absent()) { // This is local class. Add assignments for final locals and parameters. SourcePosn posn = initEncloser()->absent() ? position() : initEncloser()->position(); initEncloser(rewriteInitializer(initEncloser(), outer->finalVars(), posn)); } if ((outer->flags() & Immutable) && !params()->arity() && outer->decl()->container()->fullName() != "ti.internal" && // hack for private internal constructors isLessAccessible(flags(), outer->flags())) { // Zero-argument constructor for immutable class must be at least as // accessible as the class, since it is called when a variable of immutable // type is declared. error() << "zero-argument constructor for immutable " << outer->decl()->errorName() << " must be at least as accessible as the class" << endl; } TypeNode *mType = typeFromMethodDeclNode(this); // Check that this method is legal foriter (dd, ctx->cclass->environ()->lookupFirstProper(simpName()->ident(), Decl::Constructor), EnvironIter) if (mType->methodsConflict(dd->type())) error() << "illegal overloading of " << dd->errorName() << endl; Decl* d = new MethodDecl(ctx->cclass->name(), mType, Decl::Constructor, ctx->cclass, flags(), this); ctx->cclass->environ()->add(d); simpName()->decl(d); } void StaticInitNode::resolveClass(ClassContext *ctx) { if (ctx->methodsOnly) return; if (ctx->cclass->source()->enclosingType() && (!(ctx->cclass->modifiers() & Static) || (ctx->cclass->modifiers() & LocalClass))) error() << "inner classes cannot have static initializers" << endl; } void InstanceInitNode::resolveClass(ClassContext *ctx) { if (ctx->methodsOnly) return; } void InterfaceDeclNode::resolveClass(ClassContext *ctx) { ClassDecl &me = *decl(); if (!me.isTypeReady()) { ctx->postponed = true; return; } else if (me.visits > 1) return; bool postponed = false; ClassContext subCtx(*ctx, postponed); subCtx.cclass = &me; if (me.visits < 1) { me.visits = 1; if (enclosingType() && enclosingType()->enclosingType() && !(enclosingType()->flags() & Static)) error() << "inner classes cannot have static nested interfaces" << endl; // Member interfaces are implicitly static. else if (enclosingType()) flags((Modifiers)(flags() | Static)); // The strictfp modifier propogates to nested interfaces. if (enclosingType() && (enclosingType()->flags() & Strictfp)) flags((Modifiers)(flags() | Strictfp)); me.interfaces(NULL); foriter (interface, interfaces()->allChildren(), ChildIter) { Decl *intf = (*interface)->decl(); if (intf->category() != Decl::Interface) error() << "interface " << *decl()->declaredName() << " cannot EXTEND class " << *intf->name() << endl; else me.interfaces(cons(intf, me.interfaces())); } /* member 1 reserved for this purpose in the parser */ members()->child(1, classField(this)); } else { // All members have undergone class resolution, but methods might have // been postponed due to unavailable types. subCtx.methodsOnly = true; } members()->resolveClass(&subCtx); foriter (decl, me.environ()->allProperDecls(), EnvironIter) { int modifiers = decl->modifiers(); switch (decl->category()) { case Decl::Method: modifiers |= Public | Abstract; break; case Decl::Field: modifiers |= Public | Final | Static; break; default: break; } decl->modifiers((Modifiers) modifiers); } ctx->postponed |= postponed; me.visits = postponed ? 1 : 2; }