/* st-name.cc: Name resolution for simple and qualified names, resolve parsing ambiguities. After this phase, all fields and methods are referred to via ThisFieldAccessNode, SuperFieldAccessNode or ObjectFieldAccessNode. ObjectNode is only used for local variables and parameters. The decl in methods may be wrong, because overloading resolution is done later (when types become available) */ #include "AST.h" #include "NameContext.h" #include "compiler.h" #include "decls.h" #include "errors.h" /* Utilities */ /* Name resolution, pass 2: return a destructively modified */ /* version of *THIS, with all names resolved to ResolvedNodes and */ /* appropriate ObjectNodes re-written as field accesses. ENV is */ /* the environment in which to do the resolution. */ TreeNode* TreeNode::resolveName(const NameContext &ctx) { const int numChildren = arity(); for (int sweep = 0; sweep < numChildren; ++sweep) child(sweep, child(sweep)->resolveName(ctx)); return this; } TreeNode *CompileUnitNode::resolveName(const NameContext &ctx) { NameContext c(ctx, environ()); c.currentPackage = thePackage; types()->resolveName(c); return this; } TreeNode* FieldDeclNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); #if 0 // Not true any more (late final initialisation allowed) if ((decl()->modifiers() & Final) && initExpr()->absent()) error() << "initialiser omitted on final "<< decl()->errorName() << endl; #endif // field initialisers are part of the constructor if (ctx.currentClass->kind() == ImmutableKind) subCtx.thisModifiers = None; else subCtx.thisModifiers = (Modifiers) (Local | PolysharedQ); dtype()->resolveName(ctx); initExpr(initExpr()->resolveName(subCtx)); return this; } TreeNode* VarDeclNode::resolveName(const NameContext &ctx) { dtype()->resolveName(ctx); initExpr(initExpr()->resolveName(ctx)); if (!simpName()->decl()) { Decl *other = ctx.env->lookup(simpName()->ident(), Decl::Formal | Decl::LocalVar); if (other != NULL) error() << "declaration shadows " << other->errorName() << endl; else if ((other = ctx.env->lookupProper(simpName()->ident(), Decl::LocalVar)) != NULL) error() << "redeclaration of " << other->errorName() << endl; else { Decl* d = new LocalVarDecl(simpName()->ident(), dtype(), this, true); ctx.env->add(d); simpName()->decl(d); } } return this; } TreeNode* MethodDeclNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); subCtx.inLoop = subCtx.breakOK = NULL; const Modifiers localBit = ctx.currentClass->isImmutable() ? Local : None; subCtx.thisModifiers = (Modifiers) (flags() | localBit); Environ newEnv1(ctx.env); subCtx.env = &newEnv1; params()->resolveName(subCtx); overlaps()->resolveName(subCtx); returnType()->resolveName(ctx); throws()->resolveName(ctx); Environ newEnv2(&newEnv1); subCtx.env = &newEnv2; body(body()->resolveName(subCtx)); return this; } static void resolveOverlapName(const TreeNode::NameContext &ctx, TreeNode *name) { Decl *d0 = ctx.env->lookupProper(name->ident(), Decl::Formal); if (!d0) name->error() << "unknown parameter " << *name->ident() << " in overlap() declaration." << endl; name->decl(d0); } TreeNode* OverlapNode::resolveName(const NameContext &ctx) { resolveOverlapName(ctx, opnd0()); resolveOverlapName(ctx, opnd1()); return this; } TreeNode* MethodSignatureNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); Environ newEnv1(ctx.env); subCtx.env = &newEnv1; params()->resolveName(subCtx); returnType()->resolveName(ctx); throws()->resolveName(ctx); return this; } TreeNode* ConstructorDeclNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); subCtx.inLoop = subCtx.breakOK = NULL; subCtx.thisModifiers = flags(); Environ newEnv1(ctx.env); subCtx.env = &newEnv1; params()->resolveName(subCtx); throws()->resolveName(ctx); Environ newEnv2(&newEnv1); subCtx.env = &newEnv2; constructorCall(constructorCall()->resolveName(subCtx)); body(body()->resolveName(subCtx)); return this; } TreeNode *TemplateDeclNode::resolveName( const NameContext & ) { // : Does any formal name clash with something else, such as an // existing package or class, or the template itself? // : Does this check really belong here, or should it be // somewhere else? IdentSet values; IdentSet types; foriter (child, params()->allChildren(), ChildIter) (*child)->checkTemplateFormal( values, types ); return this; } TreeNode* TypeDeclNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx, decl()->environ()); subCtx.currentClass = decl()->asType(); members()->resolveName(subCtx); return this; } TreeNode* BlockNode::resolveName(const NameContext &ctx) { Environ newEnv(ctx.env); NameContext subCtx(ctx, &newEnv); stmts((TreeListNode *)stmts()->resolveName(subCtx)); return this; } TreeNode* LabeledStmtNode::resolveName(const NameContext &ctx) { Decl *d = label()->decl(); if (!d) { Decl *other = ctx.env->lookup(label()->ident(), Decl::StmtLabel); if (other != NULL) error() << "duplicate "<< other->errorName() << endl; d = new StmtLblDecl(label()->ident(), this); label()->decl(d); } Environ newEnv(ctx.env); NameContext subCtx(ctx, &newEnv); newEnv.add(d); stmt(stmt()->resolveName(subCtx)); return this; } TreeNode* SwitchNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); expr(expr()->resolveName(ctx)); Environ newEnv(ctx.env); subCtx.breakOK = this; subCtx.env = &newEnv; switchBlocks()->resolveName(subCtx); return this; } TreeNode* LoopNode::resolveName(const NameContext &ctx) { test(test()->resolveName(ctx)); Environ newEnv(ctx.env); NameContext subCtx(ctx, &newEnv); subCtx.breakOK = subCtx.inLoop = this; stmt(stmt()->resolveName(subCtx)); return this; } TreeNode* ForNode::resolveName(const NameContext &ctx) { Environ newEnv(ctx.env); NameContext subCtx(ctx, &newEnv); init((TreeListNode *)init()->resolveName(subCtx)); subCtx.breakOK = subCtx.inLoop = this; test(test()->resolveName(subCtx)); update((TreeListNode *)update()->resolveName(subCtx)); stmt(stmt()->resolveName(subCtx)); return this; } static TreeNode* resolveJump(TreeNode* node, TreeNode *noLabel, Environ *env) { if (node->label()->absent()) node->destination(noLabel); else { Decl *dest = env->lookup(node->label()->ident(), Decl::StmtLabel); node->label()->decl(dest); if (dest == NULL) node->error() << "label " << *node->label()->ident() << " not found" << endl; else node->destination(dest->source()->stmt()); } return node; } TreeNode* BreakNode::resolveName(const NameContext &ctx) { if (label()->absent() && ! ctx.breakOK) error() << "unlabeled break only allowed in loops or switches" << endl; resolveJump(this, ctx.breakOK, ctx.env); return this; } TreeNode* ContinueNode::resolveName(const NameContext &ctx) { if (! ctx.inLoop) error() << "unlabeled continue only allowed in loops" << endl; resolveJump(this, ctx.inLoop, ctx.env); if (destination() && !destination()->isLoop()) error() << "continue's target is not a loop" << endl; return this; } TreeNode* ParameterNode::resolveName(const NameContext &ctx) { dtype()->resolveName(ctx); if (!simpName()->decl()) { Decl *other = ctx.env->lookup(simpName()->ident(), Decl::Formal | Decl::LocalVar); if (other != NULL) { error() << "parameter shadows " << other->errorName() << endl; return this; } Decl* d = new FormalParameterDecl(simpName()->ident(), dtype(), this, !isfinal()); simpName()->decl(d); ctx.env->add(d); } return this; } TreeNode* ObjectNode::resolveName(const NameContext &ctx) { if (decl()) return this; else { const int categories = ctx.resolveAsObject ? Decl::Field | Decl::LocalVar | Decl::Formal | Decl::ConstPseudonym : Decl::Method; bool postponed = false; TreeNode * const resolved = resolveAName(name(), *ctx.env, ctx.currentClass, ctx.thisModifiers, ctx.currentPackage, categories, postponed); ctx.postponed |= postponed; return postponed ? this : resolved; } } TreeNode* ObjectFieldAccessNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); subCtx.resolveAsObject = true; object(object()->resolveName(subCtx)); return this; } TreeNode* TypeFieldAccessNode::resolveName(const NameContext &ctx) { if (!decl()) { NameContext subCtx(ctx); subCtx.resolveAsObject = true; ftype((TypeNode *)ftype()->resolveName(subCtx)); if (ctx.resolveAsObject) { TypeDecl * const typeDecl = ftype()->decl(); if (typeDecl) simpName()->decl(resolveAField(*typeDecl)); else { ctx.postponed = true; postpone( "name resolution", "type field access with unresolved container type" ); } } } return this; } TreeNode* ThisFieldAccessNode::resolveName(const NameContext &ctx) { theClass( ctx.currentClass ); flags( ctx.thisModifiers ); return TreeNode::resolveName( ctx ); } TreeNode* SuperFieldAccessNode::resolveName(const NameContext &ctx) { theClass(ctx.currentClass); flags( ctx.thisModifiers ); return TreeNode::resolveName( ctx ); } TreeNode* ThisNode::resolveName(const NameContext &ctx) { theClass(ctx.currentClass); flags(ctx.thisModifiers); return this; } TreeNode* MethodCallNode::resolveName(const NameContext &ctx) { args()->resolveName(ctx); NameContext subCtx(ctx); subCtx.resolveAsObject = false; method(method()->resolveName(subCtx)); return this; } TreeNode* CatchNode::resolveName(const NameContext &ctx) { Environ newEnv(ctx.env); NameContext subCtx(ctx, &newEnv); param(param()->resolveName(subCtx)); block(block()->resolveName(subCtx)); return this; } TreeNode* ForEachStmtNode::resolveName(const NameContext &ctx) { Environ newEnv(ctx.env); NameContext subCtx(ctx, &newEnv); // arity cannot yet be computed (no constant folding, etc), so // we give the Decls a dummy type (Point<0>). This will be fixed // later. TypeNode *ptype = makePointType(0); ptype->modifiers(Local); foriter (var, vars()->allChildren(), TreeNode::ChildIter) { (*var)->initExpr((*var)->initExpr()->resolveName(ctx)); TreeNode &simpName = *(*var)->simpName(); if (!simpName.decl()) { const string *id = simpName.ident(); Decl *other = newEnv.lookup(id, Decl::Formal); if (other != NULL) error() << "declaration shadows " << other->errorName() << endl; else { other = newEnv.lookupProper(id, Decl::Formal | Decl::LocalVar); if (other != NULL) (*var)->error() << "redeclaration of " << other->errorName() << endl; else { Decl* d = new LocalVarDecl(id, ptype, *var, false); newEnv.add(d); simpName.decl(d); } } } } subCtx.inLoop = subCtx.breakOK = this; stmt(stmt()->resolveName(subCtx)); return this; } TreeNode* PartitionStmtNode::resolveName(const NameContext &ctx) { NameContext subCtx(ctx); Environ newEnv(ctx.env); if (simpName()->absent()) subCtx.partitionEnv = ctx.env; else if (!simpName()->decl()) { Decl *other = ctx.env->lookup(simpName()->ident(), Decl::Formal); if (other != NULL) error() << "declaration shadows " << other->errorName() << endl; else { Decl* d = new LocalVarDecl(simpName()->ident(), theIntType, this, true); newEnv.add(d); simpName()->decl(d); // The new variable is not in scope in the conditions subCtx.partitionEnv = &newEnv; } } cases()->resolveName(subCtx); return this; } TreeNode *PartitionClauseNode::resolveName(const NameContext &ctx) { // The partition variable is not in scope in the condition, but is // in the statement... condition(condition()->resolveName(ctx)); NameContext subCtx(ctx, ctx.partitionEnv); stmt(stmt()->resolveName(subCtx)); return this; } // Misc support methods bool TreeNode::isLoop() const { return false; } bool ForEachStmtNode::isLoop() const { return true; } bool IterationNode::isLoop() const { return true; }