📄 attr.java
字号:
chk.validate(tree.vartype); VarSymbol v = tree.sym; if (tree.init != null) { v.pos = Position.MAXPOS; if ((v.flags_field & FINAL) != 0) { evalInit(v); } else { Type itype = attribExpr(tree.init, enter.initEnv((VarDef) tree, env), v.type); } v.pos = tree.pos; } result = tree.type = v.type; } public void visitSkip(Skip tree) { result = null; } public void visitBlock(Block tree) { if (((AttrContext) env.info).scope.owner.kind == TYP) { Env localEnv = env.dup(tree, ((AttrContext) env.info).dup( ((AttrContext) env.info).scope.dupUnshared())); ((AttrContext) localEnv.info).scope.owner = new MethodSymbol(tree.flags | BLOCK, names.empty, null, ((AttrContext) env.info).scope.owner); if ((tree.flags & STATIC) != 0) ((AttrContext) localEnv.info).staticLevel++; attribStats(tree.stats, localEnv); } else { Env localEnv = env.dup(tree, ((AttrContext) env.info).dup( ((AttrContext) env.info).scope.dup())); attribStats(tree.stats, localEnv); ((AttrContext) localEnv.info).scope.leave(); } result = null; } public void visitDoLoop(DoLoop tree) { attribStat(tree.body, env.dup(tree)); attribExpr(tree.cond, env, syms.booleanType); result = null; } public void visitWhileLoop(WhileLoop tree) { attribExpr(tree.cond, env, syms.booleanType); attribStat(tree.body, env.dup(tree)); result = null; } public void visitForLoop(ForLoop tree) { Env loopEnv = env.dup(env.tree, ((AttrContext) env.info).dup(((AttrContext) env.info).scope.dup())); attribStats(tree.init, loopEnv); if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType); loopEnv.tree = tree; attribStats(tree.step, loopEnv); attribStat(tree.body, loopEnv); ((AttrContext) loopEnv.info).scope.leave(); result = null; } public void visitLabelled(Labelled tree) { Env env1 = env; while (env1 != null && env1.tree.tag != Tree.CLASSDEF) { if (env1.tree.tag == Tree.LABELLED && ((Labelled) env1.tree).label == tree.label) { log.error(tree.pos, "label.already.in.use", tree.label.toJava()); break; } env1 = env1.next; } attribStat(tree.body, env.dup(tree)); result = null; } public void visitSwitch(Switch tree) { Type seltype = attribExpr(tree.selector, env, syms.intType); Env switchEnv = env.dup(tree, ((AttrContext) env.info).dup(((AttrContext) env.info).scope.dup())); Set labels = Set.make(); boolean hasDefault = false; for (List l = tree.cases; l.nonEmpty(); l = l.tail) { Case c = (Tree.Case) l.head; Env caseEnv = switchEnv.dup(c, ((AttrContext) env.info).dup( ((AttrContext) switchEnv.info).scope.dup())); if (c.pat != null) { Type pattype = attribExpr(c.pat, switchEnv, syms.intType); if (pattype.tag != ERROR) { if (pattype.constValue == null) { log.error(c.pat.pos, "const.expr.req"); } else if (labels.contains(pattype.constValue)) { log.error(c.pos, "duplicate.case.label"); } else { chk.checkType(c.pat.pos, pattype, seltype); labels.put(pattype.constValue); } } } else if (hasDefault) { log.error(c.pos, "duplicate.default.label"); } else { hasDefault = true; } attribStats(c.stats, caseEnv); ((AttrContext) caseEnv.info).scope.leave(); addVars(c.stats, ((AttrContext) switchEnv.info).scope); } ((AttrContext) switchEnv.info).scope.leave(); result = null; } /** * Add any variables defined in stats to the switch scope. */ private static void addVars(List stats, Scope switchScope) { for (; stats.nonEmpty(); stats = stats.tail) { Tree stat = (Tree) stats.head; if (stat.tag == Tree.VARDEF) switchScope.enter(((VarDef) stat).sym); } } public void visitSynchronized(Synchronized tree) { chk.checkRefType(tree.pos, attribExpr(tree.lock, env, syms.objectType)); attribStat(tree.body, env); result = null; } public void visitTry(Try tree) { attribStat(tree.body, env.dup(tree, ((AttrContext) env.info).dup())); for (List l = tree.catchers; l.nonEmpty(); l = l.tail) { Catch c = (Tree.Catch) l.head; Env catchEnv = env.dup(c, ((AttrContext) env.info).dup( ((AttrContext) env.info).scope.dup())); Type ctype = attribStat(c.param, catchEnv); chk.checkType(c.param.vartype.pos, ctype, syms.throwableType); attribStat(c.body, catchEnv); ((AttrContext) catchEnv.info).scope.leave(); } if (tree.finalizer != null) attribStat(tree.finalizer, env); result = null; } public void visitConditional(Conditional tree) { attribExpr(tree.cond, env, syms.booleanType); attribExpr(tree.truepart, env, pt); attribExpr(tree.falsepart, env, pt); result = check(tree, condType(tree.pos, tree.cond.type, tree.truepart.type, tree.falsepart.type), VAL, pkind, pt); } /** * Compute the type of a conditional expression, after * checking that it exists. See Spec 15.25. * * @param pos The source position to be used for error diagnostics. * @param condtype The type of the expression's condition. * @param thentype The type of the expression's then-part. * @param elsetype The type of the expression's else-part. */ private Type condType(int pos, Type condtype, Type thentype, Type elsetype) { Type ctype = condType1(pos, condtype, thentype, elsetype); return ((condtype.constValue != null) && (thentype.constValue != null) && (elsetype.constValue != null)) ? cfolder.coerce( (((Number) condtype.constValue).intValue() != 0) ? thentype : elsetype, ctype): ctype; } /** * Compute the type of a conditional expression, after * checking that it exists. Does not take into * account the special case where condition and both arms are constants. * * @param pos The source position to be used for error diagnostics. * @param condtype The type of the expression's condition. * @param thentype The type of the expression's then-part. * @param elsetype The type of the expression's else-part. */ private Type condType1(int pos, Type condtype, Type thentype, Type elsetype) { if (thentype.tag < INT && elsetype.tag == INT && elsetype.isAssignable(thentype)) return thentype.baseType(); else if (elsetype.tag < INT && thentype.tag == INT && thentype.isAssignable(elsetype)) return elsetype.baseType(); else if (thentype.tag <= DOUBLE && elsetype.tag <= DOUBLE) for (int i = BYTE; i <= DOUBLE; i++) { Type candidate = syms.typeOfTag[i]; if (thentype.isSubType(candidate) && elsetype.isSubType(candidate)) return candidate; } if (thentype.tsym == syms.stringType.tsym && elsetype.tsym == syms.stringType.tsym) return syms.stringType; else if (thentype.isSubType(elsetype)) return elsetype.baseType(); else if (elsetype.isSubType(thentype)) return thentype.baseType(); else { log.error(pos, "neither.conditional.subtype", thentype.toJava(), elsetype.toJava()); return thentype.baseType(); } } public void visitIf(If tree) { attribExpr(tree.cond, env, syms.booleanType); attribExpr(tree.thenpart, env, pt); if (tree.elsepart != null) attribExpr(tree.elsepart, env, pt); result = null; } public void visitExec(Exec tree) { attribExpr(tree.expr, env); result = null; } public void visitBreak(Break tree) { tree.target = findJumpTarget(tree.pos, tree.tag, tree.label, env); result = null; } public void visitContinue(Continue tree) { tree.target = findJumpTarget(tree.pos, tree.tag, tree.label, env); result = null; } /** * Return the target of a break or continue statement, if it exists, * report an error if not. * Note: The target of a labelled break or continue is the * (non-labelled) statement tree referred to by the label, * not the tree representing the labelled statement itself. * * @param pos The position to be used for error diagnostics * @param tag The tag of the jump statement. This is either * Tree.BREAK or Tree.CONTINUE. * @param label The label of the jump statement, or null if no * label is given. * @param env The environment current at the jump statement. */ private Tree findJumpTarget(int pos, int tag, Name label, Env env) { Env env1 = env; LOOP: while (env1 != null) { switch (env1.tree.tag) { case Tree.LABELLED: Labelled labelled = (Labelled) env1.tree; if (label == labelled.label) { if (tag == Tree.CONTINUE) { if (labelled.body.tag != Tree.DOLOOP && labelled.body.tag != Tree.WHILELOOP && labelled.body.tag != Tree.FORLOOP) log.error(pos, "not.loop.label", label.toJava()); return TreeInfo.referencedStatement(labelled); } else { return labelled; } } break; case Tree.DOLOOP: case Tree.WHILELOOP: case Tree.FORLOOP: if (label == null) return env1.tree; break; case Tree.SWITCH: if (label == null && tag == Tree.BREAK) return env1.tree; break; case Tree.METHODDEF: case Tree.CLASSDEF: break LOOP; default: } env1 = env1.next; } if (label != null) log.error(pos, "undef.label", label.toJava()); else if (tag == Tree.CONTINUE) log.error(pos, "cont.outside.loop"); else log.error(pos, "break.outside.switch.loop"); return null; } public void visitReturn(Return tree) { if (env.enclMethod == null || env.enclMethod.sym.owner != env.enclClass.sym) { log.error(tree.pos, "ret.outside.meth"); } else { Symbol m = env.enclMethod.sym; if (m.type.restype().tag == VOID) { if (tree.expr != null) log.error(tree.expr.pos, "cant.ret.val.from.meth.decl.void"); } else if (tree.expr == null) { log.error(tree.pos, "missing.ret.val"); } else { attribExpr(tree.expr, env, m.type.restype()); } } result = null; } public void visitThrow(Throw tree) { Type t = attribExpr(tree.expr, env, syms.throwableType); result = null; } public void visitAssert(Assert tree) { Type ct = attribExpr(tree.cond, env, syms.booleanType); if (tree.detail != null) { chk.checkNonVoid(tree.detail.pos, attribExpr(tree.detail, env)); } result = null; } /** * Visitor method for method invocations. * NOTE: The method part of an application will have in its type field * the return type of the method, not the method's type itself! */ public void visitApply(Apply tree) { Env localEnv = env; List argtypes; Name methName = TreeInfo.name(tree.meth); boolean isConstructorCall = methName == names._this || methName == names._super; if (isConstructorCall) { if (checkFirstConstructorStat(tree, env)) { localEnv = env.dup(env.tree, ((AttrContext) env.info).dup()); ((AttrContext) localEnv.info).isSelfCall = true; argtypes = attribArgs(tree.args, localEnv);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -