attr.java
来自「是一款用JAVA 编写的编译器 具有很强的编译功能」· Java 代码 · 共 1,568 行 · 第 1/5 页
JAVA
1,568 行
} // Attribute finalizer if (tree.finalizer != null) attribStat(tree.finalizer, env); result = null; } public void visitConditional(JCConditional tree) { attribExpr(tree.cond, env, syms.booleanType); attribExpr(tree.truepart, env); attribExpr(tree.falsepart, env); result = check(tree, capture(condType(tree.pos(), tree.cond.type, tree.truepart.type, tree.falsepart.type)), VAL, pkind, pt); } //where /** 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(DiagnosticPosition pos, Type condtype, Type thentype, Type elsetype) { Type ctype = condType1(pos, condtype, thentype, elsetype); // If condition and both arms are numeric constants, // evaluate at compile-time. return ((condtype.constValue() != null) && (thentype.constValue() != null) && (elsetype.constValue() != null)) ? cfolder.coerce(condtype.isTrue()?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(DiagnosticPosition pos, Type condtype, Type thentype, Type elsetype) { // If same type, that is the result if (types.isSameType(thentype, elsetype)) return thentype.baseType(); Type thenUnboxed = (!allowBoxing || thentype.isPrimitive()) ? thentype : types.unboxedType(thentype); Type elseUnboxed = (!allowBoxing || elsetype.isPrimitive()) ? elsetype : types.unboxedType(elsetype); // Otherwise, if both arms can be converted to a numeric // type, return the least numeric type that fits both arms // (i.e. return larger of the two, or return int if one // arm is short, the other is char). if (thenUnboxed.isPrimitive() && elseUnboxed.isPrimitive()) { // If one arm has an integer subrange type (i.e., byte, // short, or char), and the other is an integer constant // that fits into the subrange, return the subrange type. if (thenUnboxed.tag < INT && elseUnboxed.tag == INT && types.isAssignable(elseUnboxed, thenUnboxed)) return thenUnboxed.baseType(); if (elseUnboxed.tag < INT && thenUnboxed.tag == INT && types.isAssignable(thenUnboxed, elseUnboxed)) return elseUnboxed.baseType(); for (int i = BYTE; i < VOID; i++) { Type candidate = syms.typeOfTag[i]; if (types.isSubtype(thenUnboxed, candidate) && types.isSubtype(elseUnboxed, candidate)) return candidate; } } // Those were all the cases that could result in a primitive if (allowBoxing) { if (thentype.isPrimitive()) thentype = types.boxedClass(thentype).type; if (elsetype.isPrimitive()) elsetype = types.boxedClass(elsetype).type; } if (types.isSubtype(thentype, elsetype)) return elsetype.baseType(); if (types.isSubtype(elsetype, thentype)) return thentype.baseType(); if (!allowBoxing || thentype.tag == VOID || elsetype.tag == VOID) { log.error(pos, "neither.conditional.subtype", thentype, elsetype); return thentype.baseType(); } // both are known to be reference types. The result is // lub(thentype,elsetype). This cannot fail, as it will // always be possible to infer "Object" if nothing better. return types.lub(thentype.baseType(), elsetype.baseType()); } public void visitIf(JCIf tree) { attribExpr(tree.cond, env, syms.booleanType); attribStat(tree.thenpart, env); if (tree.elsepart != null) attribStat(tree.elsepart, env); chk.checkEmptyIf(tree); result = null; } public void visitExec(JCExpressionStatement tree) { attribExpr(tree.expr, env); result = null; } public void visitBreak(JCBreak tree) { tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env); result = null; } public void visitContinue(JCContinue tree) { tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env); result = null; } //where /** 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 JCTree findJumpTarget(DiagnosticPosition pos, int tag, Name label, Env<AttrContext> env) { // Search environments outwards from the point of jump. Env<AttrContext> env1 = env; LOOP: while (env1 != null) { switch (env1.tree.getTag()) { case JCTree.LABELLED: JCLabeledStatement labelled = (JCLabeledStatement)env1.tree; if (label == labelled.label) { // If jump is a continue, check that target is a loop. if (tag == JCTree.CONTINUE) { if (labelled.body.getTag() != JCTree.DOLOOP && labelled.body.getTag() != JCTree.WHILELOOP && labelled.body.getTag() != JCTree.FORLOOP && labelled.body.getTag() != JCTree.FOREACHLOOP) log.error(pos, "not.loop.label", label); // Found labelled statement target, now go inwards // to next non-labelled tree. return TreeInfo.referencedStatement(labelled); } else { return labelled; } } break; case JCTree.DOLOOP: case JCTree.WHILELOOP: case JCTree.FORLOOP: case JCTree.FOREACHLOOP: if (label == null) return env1.tree; break; case JCTree.SWITCH: if (label == null && tag == JCTree.BREAK) return env1.tree; break; case JCTree.METHODDEF: case JCTree.CLASSDEF: break LOOP; default: } env1 = env1.next; } if (label != null) log.error(pos, "undef.label", label); else if (tag == JCTree.CONTINUE) log.error(pos, "cont.outside.loop"); else log.error(pos, "break.outside.switch.loop"); return null; } public void visitReturn(JCReturn tree) { // Check that there is an enclosing method which is // nested within than the enclosing class. if (env.enclMethod == null || env.enclMethod.sym.owner != env.enclClass.sym) { log.error(tree.pos(), "ret.outside.meth"); } else { // Attribute return expression, if it exists, and check that // it conforms to result type of enclosing method. Symbol m = env.enclMethod.sym; if (m.type.getReturnType().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.getReturnType()); } } result = null; } public void visitThrow(JCThrow tree) { attribExpr(tree.expr, env, syms.throwableType); result = null; } public void visitAssert(JCAssert tree) { 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(JCMethodInvocation tree) { // The local environment of a method application is // a new environment nested in the current one. Env<AttrContext> localEnv = env.dup(tree, env.info.dup()); // The types of the actual method arguments. List<Type> argtypes; // The types of the actual method type arguments. List<Type> typeargtypes = null; Name methName = TreeInfo.name(tree.meth); boolean isConstructorCall = methName == names._this || methName == names._super; if (isConstructorCall) { // We are seeing a ...this(...) or ...super(...) call. // Check that this is the first statement in a constructor. if (checkFirstConstructorStat(tree, env)) { // Record the fact // that this is a constructor call (using isSelfCall). localEnv.info.isSelfCall = true; // Attribute arguments, yielding list of argument types. argtypes = attribArgs(tree.args, localEnv); typeargtypes = attribTypes(tree.typeargs, localEnv); // Variable `site' points to the class in which the called // constructor is defined. Type site = env.enclClass.sym.type; if (methName == names._super) { if (site == syms.objectType) { log.error(tree.meth.pos(), "no.superclass", site); site = syms.errType; } else { site = types.supertype(site); } } if (site.tag == CLASS) { if (site.getEnclosingType().tag == CLASS) { // we are calling a nested class if (tree.meth.getTag() == JCTree.SELECT) { JCTree qualifier = ((JCFieldAccess) tree.meth).selected; // We are seeing a prefixed call, of the form // <expr>.super(...). // Check that the prefix expression conforms // to the outer instance type of the class. chk.checkRefType(qualifier.pos(), attribExpr(qualifier, localEnv, site.getEnclosingType())); } else if (methName == names._super) { // qualifier omitted; check for existence // of an appropriate implicit qualifier. rs.resolveImplicitThis(tree.meth.pos(), localEnv, site); } } else if (tree.meth.getTag() == JCTree.SELECT) { log.error(tree.meth.pos(), "illegal.qual.not.icls", site.tsym); } // if we're calling a java.lang.Enum constructor, // prefix the implicit String and int parameters if (site.tsym == syms.enumSym && allowEnums) argtypes = argtypes.prepend(syms.intType).prepend(syms.stringType); // Resolve the called constructor under the assumption // that we are referring to a superclass instance of the // current instance (JLS ???).
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?