📄 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 + -