duke@1: /*
jjg@1492: * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1: *
duke@1: * This code is free software; you can redistribute it and/or modify it
duke@1: * under the terms of the GNU General Public License version 2 only, as
ohair@554: * published by the Free Software Foundation. Oracle designates this
duke@1: * particular file as subject to the "Classpath" exception as provided
ohair@554: * by Oracle in the LICENSE file that accompanied this code.
duke@1: *
duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1: * version 2 for more details (a copy is included in the LICENSE file that
duke@1: * accompanied this code).
duke@1: *
duke@1: * You should have received a copy of the GNU General Public License version
duke@1: * 2 along with this work; if not, write to the Free Software Foundation,
duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1: *
ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554: * or visit www.oracle.com if you need additional information or have any
ohair@554: * questions.
duke@1: */
duke@1:
duke@1: package com.sun.tools.javac.comp;
duke@1:
jjg@1357: import java.util.*;
jjg@1357: import java.util.Set;
jjg@1357:
jjg@1357: import javax.lang.model.element.ElementKind;
jjg@1357: import javax.tools.JavaFileObject;
duke@1:
duke@1: import com.sun.source.tree.IdentifierTree;
mcimadamore@1352: import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
duke@1: import com.sun.source.tree.MemberSelectTree;
duke@1: import com.sun.source.tree.TreeVisitor;
duke@1: import com.sun.source.util.SimpleTreeVisitor;
jjg@1357: import com.sun.tools.javac.code.*;
jjg@1357: import com.sun.tools.javac.code.Lint.LintCategory;
jjg@1357: import com.sun.tools.javac.code.Symbol.*;
jjg@1357: import com.sun.tools.javac.code.Type.*;
jjg@1357: import com.sun.tools.javac.comp.Check.CheckContext;
jjg@1357: import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
jjg@1357: import com.sun.tools.javac.comp.Infer.InferenceContext;
jjg@1357: import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
jjg@1357: import com.sun.tools.javac.jvm.*;
jjg@1357: import com.sun.tools.javac.jvm.Target;
jjg@1357: import com.sun.tools.javac.tree.*;
jjg@1357: import com.sun.tools.javac.tree.JCTree.*;
mcimadamore@1510: import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
jjg@1357: import com.sun.tools.javac.util.*;
jjg@1357: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
jjg@1357: import com.sun.tools.javac.util.List;
duke@1: import static com.sun.tools.javac.code.Flags.*;
jjg@1127: import static com.sun.tools.javac.code.Flags.ANNOTATION;
jjg@1127: import static com.sun.tools.javac.code.Flags.BLOCK;
duke@1: import static com.sun.tools.javac.code.Kinds.*;
jjg@1127: import static com.sun.tools.javac.code.Kinds.ERRONEOUS;
jjg@1374: import static com.sun.tools.javac.code.TypeTag.*;
jjg@1374: import static com.sun.tools.javac.code.TypeTag.WILDCARD;
jjg@1127: import static com.sun.tools.javac.tree.JCTree.Tag.*;
duke@1:
duke@1: /** This is the main context-dependent analysis phase in GJC. It
duke@1: * encompasses name resolution, type checking and constant folding as
duke@1: * subtasks. Some subtasks involve auxiliary classes.
duke@1: * @see Check
duke@1: * @see Resolve
duke@1: * @see ConstFold
duke@1: * @see Infer
duke@1: *
jjg@581: *
This is NOT part of any supported API.
jjg@581: * If you write code that depends on this, you do so at your own risk.
duke@1: * This code and its internal interfaces are subject to change or
duke@1: * deletion without notice.
duke@1: */
duke@1: public class Attr extends JCTree.Visitor {
duke@1: protected static final Context.Key attrKey =
duke@1: new Context.Key();
duke@1:
jjg@113: final Names names;
duke@1: final Log log;
duke@1: final Symtab syms;
duke@1: final Resolve rs;
mcimadamore@537: final Infer infer;
mcimadamore@1347: final DeferredAttr deferredAttr;
duke@1: final Check chk;
mcimadamore@1348: final Flow flow;
duke@1: final MemberEnter memberEnter;
duke@1: final TreeMaker make;
duke@1: final ConstFold cfolder;
duke@1: final Enter enter;
duke@1: final Target target;
duke@1: final Types types;
mcimadamore@89: final JCDiagnostic.Factory diags;
duke@1: final Annotate annotate;
mcimadamore@852: final DeferredLintHandler deferredLintHandler;
duke@1:
duke@1: public static Attr instance(Context context) {
duke@1: Attr instance = context.get(attrKey);
duke@1: if (instance == null)
duke@1: instance = new Attr(context);
duke@1: return instance;
duke@1: }
duke@1:
duke@1: protected Attr(Context context) {
duke@1: context.put(attrKey, this);
duke@1:
jjg@113: names = Names.instance(context);
duke@1: log = Log.instance(context);
duke@1: syms = Symtab.instance(context);
duke@1: rs = Resolve.instance(context);
duke@1: chk = Check.instance(context);
mcimadamore@1348: flow = Flow.instance(context);
duke@1: memberEnter = MemberEnter.instance(context);
duke@1: make = TreeMaker.instance(context);
duke@1: enter = Enter.instance(context);
mcimadamore@537: infer = Infer.instance(context);
mcimadamore@1347: deferredAttr = DeferredAttr.instance(context);
duke@1: cfolder = ConstFold.instance(context);
duke@1: target = Target.instance(context);
duke@1: types = Types.instance(context);
mcimadamore@89: diags = JCDiagnostic.Factory.instance(context);
duke@1: annotate = Annotate.instance(context);
mcimadamore@852: deferredLintHandler = DeferredLintHandler.instance(context);
duke@1:
duke@1: Options options = Options.instance(context);
duke@1:
duke@1: Source source = Source.instance(context);
duke@1: allowGenerics = source.allowGenerics();
duke@1: allowVarargs = source.allowVarargs();
duke@1: allowEnums = source.allowEnums();
duke@1: allowBoxing = source.allowBoxing();
duke@1: allowCovariantReturns = source.allowCovariantReturns();
duke@1: allowAnonOuterThis = source.allowAnonOuterThis();
darcy@430: allowStringsInSwitch = source.allowStringsInSwitch();
mcimadamore@1415: allowPoly = source.allowPoly();
mcimadamore@1348: allowLambda = source.allowLambda();
mcimadamore@1393: allowDefaultMethods = source.allowDefaultMethods();
darcy@430: sourceName = source.name;
jjg@700: relax = (options.isSet("-retrofit") ||
jjg@700: options.isSet("-relax"));
mcimadamore@731: findDiamonds = options.get("findDiamond") != null &&
mcimadamore@731: source.allowDiamond();
jjg@700: useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
mcimadamore@1348: identifyLambdaCandidate = options.getBoolean("identifyLambdaCandidate", false);
mcimadamore@1238:
mcimadamore@1238: statInfo = new ResultInfo(NIL, Type.noType);
mcimadamore@1238: varInfo = new ResultInfo(VAR, Type.noType);
mcimadamore@1238: unknownExprInfo = new ResultInfo(VAL, Type.noType);
mcimadamore@1238: unknownTypeInfo = new ResultInfo(TYP, Type.noType);
mcimadamore@1348: recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
duke@1: }
duke@1:
duke@1: /** Switch: relax some constraints for retrofit mode.
duke@1: */
duke@1: boolean relax;
duke@1:
mcimadamore@1347: /** Switch: support target-typing inference
mcimadamore@1347: */
mcimadamore@1347: boolean allowPoly;
mcimadamore@1347:
duke@1: /** Switch: support generics?
duke@1: */
duke@1: boolean allowGenerics;
duke@1:
duke@1: /** Switch: allow variable-arity methods.
duke@1: */
duke@1: boolean allowVarargs;
duke@1:
duke@1: /** Switch: support enums?
duke@1: */
duke@1: boolean allowEnums;
duke@1:
duke@1: /** Switch: support boxing and unboxing?
duke@1: */
duke@1: boolean allowBoxing;
duke@1:
duke@1: /** Switch: support covariant result types?
duke@1: */
duke@1: boolean allowCovariantReturns;
duke@1:
mcimadamore@1415: /** Switch: support lambda expressions ?
mcimadamore@1415: */
mcimadamore@1415: boolean allowLambda;
mcimadamore@1415:
mcimadamore@1393: /** Switch: support default methods ?
mcimadamore@1393: */
mcimadamore@1393: boolean allowDefaultMethods;
mcimadamore@1393:
duke@1: /** Switch: allow references to surrounding object from anonymous
duke@1: * objects during constructor call?
duke@1: */
duke@1: boolean allowAnonOuterThis;
duke@1:
mcimadamore@731: /** Switch: generates a warning if diamond can be safely applied
mcimadamore@731: * to a given new expression
mcimadamore@731: */
mcimadamore@731: boolean findDiamonds;
mcimadamore@731:
mcimadamore@731: /**
mcimadamore@731: * Internally enables/disables diamond finder feature
mcimadamore@731: */
mcimadamore@731: static final boolean allowDiamondFinder = true;
mcimadamore@731:
duke@1: /**
duke@1: * Switch: warn about use of variable before declaration?
duke@1: * RFE: 6425594
duke@1: */
duke@1: boolean useBeforeDeclarationWarning;
duke@1:
jjg@377: /**
mcimadamore@1348: * Switch: generate warnings whenever an anonymous inner class that is convertible
mcimadamore@1348: * to a lambda expression is found
mcimadamore@1348: */
mcimadamore@1348: boolean identifyLambdaCandidate;
mcimadamore@1348:
mcimadamore@1348: /**
darcy@430: * Switch: allow strings in switch?
darcy@430: */
darcy@430: boolean allowStringsInSwitch;
darcy@430:
darcy@430: /**
darcy@430: * Switch: name of source level; used for error reporting.
darcy@430: */
darcy@430: String sourceName;
darcy@430:
duke@1: /** Check kind and type of given tree against protokind and prototype.
duke@1: * If check succeeds, store type in tree and return it.
duke@1: * If check fails, store errType in tree and return it.
duke@1: * No checks are performed if the prototype is a method type.
jjg@110: * It is not necessary in this case since we know that kind and type
duke@1: * are correct.
duke@1: *
duke@1: * @param tree The tree whose kind and type is checked
duke@1: * @param ownkind The computed kind of the tree
mcimadamore@1220: * @param resultInfo The expected result of the tree
duke@1: */
mcimadamore@1347: Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
mcimadamore@1347: InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
mcimadamore@1347: Type owntype = found;
jjg@1374: if (!owntype.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
mcimadamore@1347: if (inferenceContext.free(found)) {
mcimadamore@1347: inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
mcimadamore@1347: @Override
mcimadamore@1347: public void typesInferred(InferenceContext inferenceContext) {
mcimadamore@1347: ResultInfo pendingResult =
mcimadamore@1347: resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types));
mcimadamore@1347: check(tree, inferenceContext.asInstType(found, types), ownkind, pendingResult);
mcimadamore@1347: }
mcimadamore@1347: });
mcimadamore@1347: return tree.type = resultInfo.pt;
duke@1: } else {
mcimadamore@1347: if ((ownkind & ~resultInfo.pkind) == 0) {
mcimadamore@1347: owntype = resultInfo.check(tree, owntype);
mcimadamore@1347: } else {
mcimadamore@1347: log.error(tree.pos(), "unexpected.type",
mcimadamore@1347: kindNames(resultInfo.pkind),
mcimadamore@1347: kindName(ownkind));
mcimadamore@1347: owntype = types.createErrorType(owntype);
mcimadamore@1347: }
duke@1: }
duke@1: }
duke@1: tree.type = owntype;
duke@1: return owntype;
duke@1: }
duke@1:
duke@1: /** Is given blank final variable assignable, i.e. in a scope where it
duke@1: * may be assigned to even though it is final?
duke@1: * @param v The blank final variable.
duke@1: * @param env The current environment.
duke@1: */
duke@1: boolean isAssignableAsBlankFinal(VarSymbol v, Env env) {
mcimadamore@1297: Symbol owner = owner(env);
duke@1: // owner refers to the innermost variable, method or
duke@1: // initializer block declaration at this point.
duke@1: return
duke@1: v.owner == owner
duke@1: ||
duke@1: ((owner.name == names.init || // i.e. we are in a constructor
duke@1: owner.kind == VAR || // i.e. we are in a variable initializer
duke@1: (owner.flags() & BLOCK) != 0) // i.e. we are in an initializer block
duke@1: &&
duke@1: v.owner == owner.owner
duke@1: &&
duke@1: ((v.flags() & STATIC) != 0) == Resolve.isStatic(env));
duke@1: }
duke@1:
mcimadamore@1297: /**
mcimadamore@1297: * Return the innermost enclosing owner symbol in a given attribution context
mcimadamore@1297: */
mcimadamore@1297: Symbol owner(Env env) {
mcimadamore@1297: while (true) {
mcimadamore@1297: switch (env.tree.getTag()) {
mcimadamore@1297: case VARDEF:
mcimadamore@1297: //a field can be owner
mcimadamore@1297: VarSymbol vsym = ((JCVariableDecl)env.tree).sym;
mcimadamore@1297: if (vsym.owner.kind == TYP) {
mcimadamore@1297: return vsym;
mcimadamore@1297: }
mcimadamore@1297: break;
mcimadamore@1297: case METHODDEF:
mcimadamore@1297: //method def is always an owner
mcimadamore@1297: return ((JCMethodDecl)env.tree).sym;
mcimadamore@1297: case CLASSDEF:
mcimadamore@1297: //class def is always an owner
mcimadamore@1297: return ((JCClassDecl)env.tree).sym;
mcimadamore@1348: case LAMBDA:
mcimadamore@1348: //a lambda is an owner - return a fresh synthetic method symbol
mcimadamore@1348: return new MethodSymbol(0, names.empty, null, syms.methodClass);
mcimadamore@1297: case BLOCK:
mcimadamore@1297: //static/instance init blocks are owner
mcimadamore@1297: Symbol blockSym = env.info.scope.owner;
mcimadamore@1297: if ((blockSym.flags() & BLOCK) != 0) {
mcimadamore@1297: return blockSym;
mcimadamore@1297: }
mcimadamore@1297: break;
mcimadamore@1297: case TOPLEVEL:
mcimadamore@1297: //toplevel is always an owner (for pkge decls)
mcimadamore@1297: return env.info.scope.owner;
mcimadamore@1297: }
mcimadamore@1297: Assert.checkNonNull(env.next);
mcimadamore@1297: env = env.next;
mcimadamore@1297: }
mcimadamore@1297: }
mcimadamore@1297:
duke@1: /** Check that variable can be assigned to.
duke@1: * @param pos The current source code position.
duke@1: * @param v The assigned varaible
duke@1: * @param base If the variable is referred to in a Select, the part
duke@1: * to the left of the `.', null otherwise.
duke@1: * @param env The current environment.
duke@1: */
duke@1: void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env env) {
duke@1: if ((v.flags() & FINAL) != 0 &&
duke@1: ((v.flags() & HASINIT) != 0
duke@1: ||
duke@1: !((base == null ||
jjg@1127: (base.hasTag(IDENT) && TreeInfo.name(base) == names._this)) &&
duke@1: isAssignableAsBlankFinal(v, env)))) {
darcy@609: if (v.isResourceVariable()) { //TWR resource
mcimadamore@743: log.error(pos, "try.resource.may.not.be.assigned", v);
darcy@609: } else {
darcy@609: log.error(pos, "cant.assign.val.to.final.var", v);
darcy@609: }
duke@1: }
duke@1: }
duke@1:
duke@1: /** Does tree represent a static reference to an identifier?
duke@1: * It is assumed that tree is either a SELECT or an IDENT.
duke@1: * We have to weed out selects from non-type names here.
duke@1: * @param tree The candidate tree.
duke@1: */
duke@1: boolean isStaticReference(JCTree tree) {
jjg@1127: if (tree.hasTag(SELECT)) {
duke@1: Symbol lsym = TreeInfo.symbol(((JCFieldAccess) tree).selected);
duke@1: if (lsym == null || lsym.kind != TYP) {
duke@1: return false;
duke@1: }
duke@1: }
duke@1: return true;
duke@1: }
duke@1:
duke@1: /** Is this symbol a type?
duke@1: */
duke@1: static boolean isType(Symbol sym) {
duke@1: return sym != null && sym.kind == TYP;
duke@1: }
duke@1:
duke@1: /** The current `this' symbol.
duke@1: * @param env The current environment.
duke@1: */
duke@1: Symbol thisSym(DiagnosticPosition pos, Env env) {
duke@1: return rs.resolveSelf(pos, env, env.enclClass.sym, names._this);
duke@1: }
duke@1:
duke@1: /** Attribute a parsed identifier.
duke@1: * @param tree Parsed identifier name
duke@1: * @param topLevel The toplevel to use
duke@1: */
duke@1: public Symbol attribIdent(JCTree tree, JCCompilationUnit topLevel) {
duke@1: Env localEnv = enter.topLevelEnv(topLevel);
duke@1: localEnv.enclClass = make.ClassDef(make.Modifiers(0),
duke@1: syms.errSymbol.name,
duke@1: null, null, null, null);
duke@1: localEnv.enclClass.sym = syms.errSymbol;
duke@1: return tree.accept(identAttributer, localEnv);
duke@1: }
duke@1: // where
duke@1: private TreeVisitor> identAttributer = new IdentAttributer();
duke@1: private class IdentAttributer extends SimpleTreeVisitor> {
duke@1: @Override
duke@1: public Symbol visitMemberSelect(MemberSelectTree node, Env env) {
duke@1: Symbol site = visit(node.getExpression(), env);
duke@1: if (site.kind == ERR)
duke@1: return site;
duke@1: Name name = (Name)node.getIdentifier();
duke@1: if (site.kind == PCK) {
duke@1: env.toplevel.packge = (PackageSymbol)site;
duke@1: return rs.findIdentInPackage(env, (TypeSymbol)site, name, TYP | PCK);
duke@1: } else {
duke@1: env.enclClass.sym = (ClassSymbol)site;
duke@1: return rs.findMemberType(env, site.asType(), name, (TypeSymbol)site);
duke@1: }
duke@1: }
duke@1:
duke@1: @Override
duke@1: public Symbol visitIdentifier(IdentifierTree node, Env env) {
duke@1: return rs.findIdent(env, (Name)node.getName(), TYP | PCK);
duke@1: }
duke@1: }
duke@1:
duke@1: public Type coerce(Type etype, Type ttype) {
duke@1: return cfolder.coerce(etype, ttype);
duke@1: }
duke@1:
duke@1: public Type attribType(JCTree node, TypeSymbol sym) {
duke@1: Env env = enter.typeEnvs.get(sym);
duke@1: Env localEnv = env.dup(node, env.info.dup());
mcimadamore@1220: return attribTree(node, localEnv, unknownTypeInfo);
mcimadamore@1220: }
mcimadamore@1220:
mcimadamore@1220: public Type attribImportQualifier(JCImport tree, Env env) {
mcimadamore@1220: // Attribute qualifying package or class.
mcimadamore@1220: JCFieldAccess s = (JCFieldAccess)tree.qualid;
mcimadamore@1220: return attribTree(s.selected,
mcimadamore@1220: env,
mcimadamore@1220: new ResultInfo(tree.staticImport ? TYP : (TYP | PCK),
mcimadamore@1220: Type.noType));
duke@1: }
duke@1:
duke@1: public Env attribExprToTree(JCTree expr, Env env, JCTree tree) {
duke@1: breakTree = tree;
mcimadamore@303: JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
duke@1: try {
duke@1: attribExpr(expr, env);
duke@1: } catch (BreakAttr b) {
duke@1: return b.env;
sundar@669: } catch (AssertionError ae) {
sundar@669: if (ae.getCause() instanceof BreakAttr) {
sundar@669: return ((BreakAttr)(ae.getCause())).env;
sundar@669: } else {
sundar@669: throw ae;
sundar@669: }
duke@1: } finally {
duke@1: breakTree = null;
duke@1: log.useSource(prev);
duke@1: }
duke@1: return env;
duke@1: }
duke@1:
duke@1: public Env attribStatToTree(JCTree stmt, Env env, JCTree tree) {
duke@1: breakTree = tree;
mcimadamore@303: JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
duke@1: try {
duke@1: attribStat(stmt, env);
duke@1: } catch (BreakAttr b) {
duke@1: return b.env;
sundar@669: } catch (AssertionError ae) {
sundar@669: if (ae.getCause() instanceof BreakAttr) {
sundar@669: return ((BreakAttr)(ae.getCause())).env;
sundar@669: } else {
sundar@669: throw ae;
sundar@669: }
duke@1: } finally {
duke@1: breakTree = null;
duke@1: log.useSource(prev);
duke@1: }
duke@1: return env;
duke@1: }
duke@1:
duke@1: private JCTree breakTree = null;
duke@1:
duke@1: private static class BreakAttr extends RuntimeException {
duke@1: static final long serialVersionUID = -6924771130405446405L;
duke@1: private Env env;
duke@1: private BreakAttr(Env env) {
mcimadamore@1347: this.env = copyEnv(env);
mcimadamore@1347: }
mcimadamore@1347:
mcimadamore@1347: private Env copyEnv(Env env) {
mcimadamore@1347: Env newEnv =
mcimadamore@1347: env.dup(env.tree, env.info.dup(copyScope(env.info.scope)));
mcimadamore@1347: if (newEnv.outer != null) {
mcimadamore@1347: newEnv.outer = copyEnv(newEnv.outer);
mcimadamore@1347: }
mcimadamore@1347: return newEnv;
mcimadamore@1347: }
mcimadamore@1347:
mcimadamore@1347: private Scope copyScope(Scope sc) {
mcimadamore@1347: Scope newScope = new Scope(sc.owner);
mcimadamore@1347: List elemsList = List.nil();
mcimadamore@1347: while (sc != null) {
mcimadamore@1347: for (Scope.Entry e = sc.elems ; e != null ; e = e.sibling) {
mcimadamore@1347: elemsList = elemsList.prepend(e.sym);
mcimadamore@1347: }
mcimadamore@1347: sc = sc.next;
mcimadamore@1347: }
mcimadamore@1347: for (Symbol s : elemsList) {
mcimadamore@1347: newScope.enter(s);
mcimadamore@1347: }
mcimadamore@1347: return newScope;
duke@1: }
duke@1: }
duke@1:
mcimadamore@1238: class ResultInfo {
mcimadamore@1347: final int pkind;
mcimadamore@1347: final Type pt;
mcimadamore@1347: final CheckContext checkContext;
mcimadamore@1220:
mcimadamore@1220: ResultInfo(int pkind, Type pt) {
mcimadamore@1238: this(pkind, pt, chk.basicHandler);
mcimadamore@1238: }
mcimadamore@1238:
mcimadamore@1238: protected ResultInfo(int pkind, Type pt, CheckContext checkContext) {
mcimadamore@1220: this.pkind = pkind;
mcimadamore@1220: this.pt = pt;
mcimadamore@1238: this.checkContext = checkContext;
mcimadamore@1238: }
mcimadamore@1238:
mcimadamore@1347: protected Type check(final DiagnosticPosition pos, final Type found) {
mcimadamore@1238: return chk.checkType(pos, found, pt, checkContext);
mcimadamore@1220: }
mcimadamore@1347:
mcimadamore@1347: protected ResultInfo dup(Type newPt) {
mcimadamore@1347: return new ResultInfo(pkind, newPt, checkContext);
mcimadamore@1347: }
mcimadamore@1415:
mcimadamore@1415: protected ResultInfo dup(CheckContext newContext) {
mcimadamore@1415: return new ResultInfo(pkind, pt, newContext);
mcimadamore@1415: }
mcimadamore@1220: }
mcimadamore@1220:
mcimadamore@1348: class RecoveryInfo extends ResultInfo {
mcimadamore@1348:
mcimadamore@1348: public RecoveryInfo(final DeferredAttr.DeferredAttrContext deferredAttrContext) {
mcimadamore@1348: super(Kinds.VAL, Type.recoveryType, new Check.NestedCheckContext(chk.basicHandler) {
mcimadamore@1348: @Override
mcimadamore@1348: public DeferredAttr.DeferredAttrContext deferredAttrContext() {
mcimadamore@1348: return deferredAttrContext;
mcimadamore@1348: }
mcimadamore@1348: @Override
mcimadamore@1348: public boolean compatible(Type found, Type req, Warner warn) {
mcimadamore@1348: return true;
mcimadamore@1348: }
mcimadamore@1348: @Override
mcimadamore@1348: public void report(DiagnosticPosition pos, JCDiagnostic details) {
mcimadamore@1415: chk.basicHandler.report(pos, details);
mcimadamore@1348: }
mcimadamore@1348: });
mcimadamore@1348: }
mcimadamore@1348:
mcimadamore@1348: @Override
mcimadamore@1348: protected Type check(DiagnosticPosition pos, Type found) {
mcimadamore@1348: return chk.checkNonVoid(pos, super.check(pos, found));
mcimadamore@1348: }
mcimadamore@1348: }
mcimadamore@1348:
mcimadamore@1347: final ResultInfo statInfo;
mcimadamore@1347: final ResultInfo varInfo;
mcimadamore@1347: final ResultInfo unknownExprInfo;
mcimadamore@1347: final ResultInfo unknownTypeInfo;
mcimadamore@1348: final ResultInfo recoveryInfo;
mcimadamore@1220:
mcimadamore@1220: Type pt() {
mcimadamore@1220: return resultInfo.pt;
mcimadamore@1220: }
mcimadamore@1220:
mcimadamore@1220: int pkind() {
mcimadamore@1220: return resultInfo.pkind;
mcimadamore@1220: }
duke@1:
duke@1: /* ************************************************************************
duke@1: * Visitor methods
duke@1: *************************************************************************/
duke@1:
duke@1: /** Visitor argument: the current environment.
duke@1: */
duke@1: Env env;
duke@1:
mcimadamore@1220: /** Visitor argument: the currently expected attribution result.
duke@1: */
mcimadamore@1220: ResultInfo resultInfo;
duke@1:
duke@1: /** Visitor result: the computed type.
duke@1: */
duke@1: Type result;
duke@1:
duke@1: /** Visitor method: attribute a tree, catching any completion failure
duke@1: * exceptions. Return the tree's type.
duke@1: *
duke@1: * @param tree The tree to be visited.
duke@1: * @param env The environment visitor argument.
mcimadamore@1220: * @param resultInfo The result info visitor argument.
duke@1: */
mcimadamore@1347: Type attribTree(JCTree tree, Env env, ResultInfo resultInfo) {
duke@1: Env prevEnv = this.env;
mcimadamore@1220: ResultInfo prevResult = this.resultInfo;
duke@1: try {
duke@1: this.env = env;
mcimadamore@1220: this.resultInfo = resultInfo;
duke@1: tree.accept(this);
mcimadamore@1415: if (tree == breakTree &&
mcimadamore@1415: resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
duke@1: throw new BreakAttr(env);
mcimadamore@1415: }
duke@1: return result;
duke@1: } catch (CompletionFailure ex) {
duke@1: tree.type = syms.errType;
duke@1: return chk.completionError(tree.pos(), ex);
duke@1: } finally {
duke@1: this.env = prevEnv;
mcimadamore@1220: this.resultInfo = prevResult;
duke@1: }
duke@1: }
duke@1:
duke@1: /** Derived visitor method: attribute an expression tree.
duke@1: */
duke@1: public Type attribExpr(JCTree tree, Env env, Type pt) {
jjg@1374: return attribTree(tree, env, new ResultInfo(VAL, !pt.hasTag(ERROR) ? pt : Type.noType));
darcy@609: }
darcy@609:
duke@1: /** Derived visitor method: attribute an expression tree with
duke@1: * no constraints on the computed type.
duke@1: */
jjg@1409: public Type attribExpr(JCTree tree, Env env) {
mcimadamore@1220: return attribTree(tree, env, unknownExprInfo);
duke@1: }
duke@1:
duke@1: /** Derived visitor method: attribute a type tree.
duke@1: */
jjg@1409: public Type attribType(JCTree tree, Env env) {
mcimadamore@537: Type result = attribType(tree, env, Type.noType);
mcimadamore@537: return result;
mcimadamore@537: }
mcimadamore@537:
mcimadamore@537: /** Derived visitor method: attribute a type tree.
mcimadamore@537: */
mcimadamore@537: Type attribType(JCTree tree, Env env, Type pt) {
mcimadamore@1220: Type result = attribTree(tree, env, new ResultInfo(TYP, pt));
duke@1: return result;
duke@1: }
duke@1:
duke@1: /** Derived visitor method: attribute a statement or definition tree.
duke@1: */
duke@1: public Type attribStat(JCTree tree, Env env) {
mcimadamore@1220: return attribTree(tree, env, statInfo);
duke@1: }
duke@1:
duke@1: /** Attribute a list of expressions, returning a list of types.
duke@1: */
duke@1: List attribExprs(List trees, Env env, Type pt) {
duke@1: ListBuffer ts = new ListBuffer();
duke@1: for (List l = trees; l.nonEmpty(); l = l.tail)
duke@1: ts.append(attribExpr(l.head, env, pt));
duke@1: return ts.toList();
duke@1: }
duke@1:
duke@1: /** Attribute a list of statements, returning nothing.
duke@1: */
duke@1: void attribStats(List trees, Env env) {
duke@1: for (List l = trees; l.nonEmpty(); l = l.tail)
duke@1: attribStat(l.head, env);
duke@1: }
duke@1:
duke@1: /** Attribute the arguments in a method call, returning a list of types.
duke@1: */
duke@1: List attribArgs(List trees, Env env) {
duke@1: ListBuffer argtypes = new ListBuffer();
mcimadamore@1347: for (JCExpression arg : trees) {
mcimadamore@1347: Type argtype = allowPoly && TreeInfo.isPoly(arg, env.tree) ?
mcimadamore@1347: deferredAttr.new DeferredType(arg, env) :
mcimadamore@1347: chk.checkNonVoid(arg, attribExpr(arg, env, Infer.anyPoly));
mcimadamore@1347: argtypes.append(argtype);
mcimadamore@1347: }
duke@1: return argtypes.toList();
duke@1: }
duke@1:
duke@1: /** Attribute a type argument list, returning a list of types.
jrose@267: * Caller is responsible for calling checkRefTypes.
duke@1: */
jrose@267: List attribAnyTypes(List trees, Env env) {
duke@1: ListBuffer argtypes = new ListBuffer();
duke@1: for (List l = trees; l.nonEmpty(); l = l.tail)
jrose@267: argtypes.append(attribType(l.head, env));
duke@1: return argtypes.toList();
duke@1: }
duke@1:
jrose@267: /** Attribute a type argument list, returning a list of types.
jrose@267: * Check that all the types are references.
jrose@267: */
jrose@267: List attribTypes(List trees, Env env) {
jrose@267: List types = attribAnyTypes(trees, env);
jrose@267: return chk.checkRefTypes(trees, types);
jrose@267: }
duke@1:
duke@1: /**
duke@1: * Attribute type variables (of generic classes or methods).
duke@1: * Compound types are attributed later in attribBounds.
duke@1: * @param typarams the type variables to enter
duke@1: * @param env the current environment
duke@1: */
duke@1: void attribTypeVariables(List typarams, Env env) {
duke@1: for (JCTypeParameter tvar : typarams) {
duke@1: TypeVar a = (TypeVar)tvar.type;
mcimadamore@42: a.tsym.flags_field |= UNATTRIBUTED;
mcimadamore@42: a.bound = Type.noType;
duke@1: if (!tvar.bounds.isEmpty()) {
duke@1: List bounds = List.of(attribType(tvar.bounds.head, env));
duke@1: for (JCExpression bound : tvar.bounds.tail)
duke@1: bounds = bounds.prepend(attribType(bound, env));
duke@1: types.setBounds(a, bounds.reverse());
duke@1: } else {
duke@1: // if no bounds are given, assume a single bound of
duke@1: // java.lang.Object.
duke@1: types.setBounds(a, List.of(syms.objectType));
duke@1: }
mcimadamore@42: a.tsym.flags_field &= ~UNATTRIBUTED;
duke@1: }
mcimadamore@1436: for (JCTypeParameter tvar : typarams) {
duke@1: chk.checkNonCyclic(tvar.pos(), (TypeVar)tvar.type);
duke@1: }
duke@1: }
duke@1:
duke@1: /**
duke@1: * Attribute the type references in a list of annotations.
duke@1: */
duke@1: void attribAnnotationTypes(List annotations,
duke@1: Env env) {
duke@1: for (List al = annotations; al.nonEmpty(); al = al.tail) {
duke@1: JCAnnotation a = al.head;
duke@1: attribType(a.annotationType, env);
duke@1: }
duke@1: }
duke@1:
jjg@841: /**
jjg@841: * Attribute a "lazy constant value".
jjg@841: * @param env The env for the const value
jjg@841: * @param initializer The initializer for the const value
jjg@841: * @param type The expected type, or null
jjg@1358: * @see VarSymbol#setLazyConstValue
jjg@841: */
jjg@841: public Object attribLazyConstantValue(Env env,
jjg@841: JCTree.JCExpression initializer,
jjg@841: Type type) {
jjg@841:
jjg@841: // in case no lint value has been set up for this env, scan up
jjg@841: // env stack looking for smallest enclosing env for which it is set.
jjg@841: Env lintEnv = env;
jjg@841: while (lintEnv.info.lint == null)
jjg@841: lintEnv = lintEnv.next;
jjg@841:
jjg@841: // Having found the enclosing lint value, we can initialize the lint value for this class
jjg@1078: // ... but ...
jjg@1078: // There's a problem with evaluating annotations in the right order, such that
jjg@1078: // env.info.enclVar.attributes_field might not yet have been evaluated, and so might be
jjg@1078: // null. In that case, calling augment will throw an NPE. To avoid this, for now we
jjg@1078: // revert to the jdk 6 behavior and ignore the (unevaluated) attributes.
jfranck@1313: if (env.info.enclVar.annotations.pendingCompletion()) {
jjg@1078: env.info.lint = lintEnv.info.lint;
jfranck@1313: } else {
jfranck@1313: env.info.lint = lintEnv.info.lint.augment(env.info.enclVar.annotations,
jfranck@1313: env.info.enclVar.flags());
jfranck@1313: }
jjg@841:
jjg@841: Lint prevLint = chk.setLint(env.info.lint);
jjg@841: JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
jjg@841:
jjg@841: try {
jjg@841: Type itype = attribExpr(initializer, env, type);
jjg@841: if (itype.constValue() != null)
jjg@841: return coerce(itype, type).constValue();
jjg@841: else
jjg@841: return null;
jjg@841: } finally {
jjg@841: env.info.lint = prevLint;
jjg@841: log.useSource(prevSource);
jjg@841: }
jjg@841: }
jjg@841:
duke@1: /** Attribute type reference in an `extends' or `implements' clause.
mcimadamore@537: * Supertypes of anonymous inner classes are usually already attributed.
duke@1: *
duke@1: * @param tree The tree making up the type reference.
duke@1: * @param env The environment current at the reference.
duke@1: * @param classExpected true if only a class is expected here.
duke@1: * @param interfaceExpected true if only an interface is expected here.
duke@1: */
duke@1: Type attribBase(JCTree tree,
duke@1: Env env,
duke@1: boolean classExpected,
duke@1: boolean interfaceExpected,
duke@1: boolean checkExtensible) {
mcimadamore@537: Type t = tree.type != null ?
mcimadamore@537: tree.type :
mcimadamore@537: attribType(tree, env);
duke@1: return checkBase(t, tree, env, classExpected, interfaceExpected, checkExtensible);
duke@1: }
duke@1: Type checkBase(Type t,
duke@1: JCTree tree,
duke@1: Env env,
duke@1: boolean classExpected,
duke@1: boolean interfaceExpected,
duke@1: boolean checkExtensible) {
jjg@664: if (t.isErroneous())
jjg@664: return t;
jjg@1374: if (t.hasTag(TYPEVAR) && !classExpected && !interfaceExpected) {
duke@1: // check that type variable is already visible
duke@1: if (t.getUpperBound() == null) {
duke@1: log.error(tree.pos(), "illegal.forward.ref");
jjg@110: return types.createErrorType(t);
duke@1: }
duke@1: } else {
duke@1: t = chk.checkClassType(tree.pos(), t, checkExtensible|!allowGenerics);
duke@1: }
duke@1: if (interfaceExpected && (t.tsym.flags() & INTERFACE) == 0) {
duke@1: log.error(tree.pos(), "intf.expected.here");
duke@1: // return errType is necessary since otherwise there might
duke@1: // be undetected cycles which cause attribution to loop
jjg@110: return types.createErrorType(t);
duke@1: } else if (checkExtensible &&
duke@1: classExpected &&
duke@1: (t.tsym.flags() & INTERFACE) != 0) {
jjg@664: log.error(tree.pos(), "no.intf.expected.here");
jjg@110: return types.createErrorType(t);
duke@1: }
duke@1: if (checkExtensible &&
duke@1: ((t.tsym.flags() & FINAL) != 0)) {
duke@1: log.error(tree.pos(),
duke@1: "cant.inherit.from.final", t.tsym);
duke@1: }
duke@1: chk.checkNonCyclic(tree.pos(), t);
duke@1: return t;
duke@1: }
duke@1:
mcimadamore@1269: Type attribIdentAsEnumType(Env env, JCIdent id) {
mcimadamore@1269: Assert.check((env.enclClass.sym.flags() & ENUM) != 0);
mcimadamore@1269: id.type = env.info.scope.owner.type;
mcimadamore@1269: id.sym = env.info.scope.owner;
mcimadamore@1269: return id.type;
mcimadamore@1269: }
mcimadamore@1269:
duke@1: public void visitClassDef(JCClassDecl tree) {
duke@1: // Local classes have not been entered yet, so we need to do it now:
duke@1: if ((env.info.scope.owner.kind & (VAR | MTH)) != 0)
duke@1: enter.classEnter(tree, env);
duke@1:
duke@1: ClassSymbol c = tree.sym;
duke@1: if (c == null) {
duke@1: // exit in case something drastic went wrong during enter.
duke@1: result = null;
duke@1: } else {
duke@1: // make sure class has been completed:
duke@1: c.complete();
duke@1:
duke@1: // If this class appears as an anonymous class
duke@1: // in a superclass constructor call where
duke@1: // no explicit outer instance is given,
duke@1: // disable implicit outer instance from being passed.
duke@1: // (This would be an illegal access to "this before super").
duke@1: if (env.info.isSelfCall &&
jjg@1127: env.tree.hasTag(NEWCLASS) &&
duke@1: ((JCNewClass) env.tree).encl == null)
duke@1: {
duke@1: c.flags_field |= NOOUTERTHIS;
duke@1: }
duke@1: attribClass(tree.pos(), c);
duke@1: result = tree.type = c.type;
duke@1: }
duke@1: }
duke@1:
duke@1: public void visitMethodDef(JCMethodDecl tree) {
duke@1: MethodSymbol m = tree.sym;
mcimadamore@1366: boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
duke@1:
jfranck@1313: Lint lint = env.info.lint.augment(m.annotations, m.flags());
duke@1: Lint prevLint = chk.setLint(lint);
mcimadamore@795: MethodSymbol prevMethod = chk.setMethod(m);
duke@1: try {
mcimadamore@852: deferredLintHandler.flush(tree.pos());
duke@1: chk.checkDeprecatedAnnotation(tree.pos(), m);
duke@1:
mcimadamore@1436: // Create a new environment with local scope
mcimadamore@1436: // for attributing the method.
mcimadamore@1436: Env localEnv = memberEnter.methodEnv(tree, env);
mcimadamore@1436: localEnv.info.lint = lint;
mcimadamore@1436:
mcimadamore@1436: attribStats(tree.typarams, localEnv);
duke@1:
duke@1: // If we override any other methods, check that we do so properly.
duke@1: // JLS ???
mcimadamore@858: if (m.isStatic()) {
mcimadamore@858: chk.checkHideClashes(tree.pos(), env.enclClass.type, m);
mcimadamore@858: } else {
mcimadamore@858: chk.checkOverrideClashes(tree.pos(), env.enclClass.type, m);
mcimadamore@858: }
duke@1: chk.checkOverride(tree, m);
duke@1:
mcimadamore@1415: if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) {
mcimadamore@1393: log.error(tree, "default.overrides.object.member", m.name, Kinds.kindName(m.location()), m.location());
mcimadamore@1393: }
mcimadamore@1393:
duke@1: // Enter all type parameters into the local method scope.
duke@1: for (List l = tree.typarams; l.nonEmpty(); l = l.tail)
duke@1: localEnv.info.scope.enterIfAbsent(l.head.type.tsym);
duke@1:
duke@1: ClassSymbol owner = env.enclClass.sym;
duke@1: if ((owner.flags() & ANNOTATION) != 0 &&
duke@1: tree.params.nonEmpty())
duke@1: log.error(tree.params.head.pos(),
duke@1: "intf.annotation.members.cant.have.params");
duke@1:
duke@1: // Attribute all value parameters.
duke@1: for (List l = tree.params; l.nonEmpty(); l = l.tail) {
duke@1: attribStat(l.head, localEnv);
duke@1: }
duke@1:
mcimadamore@795: chk.checkVarargsMethodDecl(localEnv, tree);
mcimadamore@580:
duke@1: // Check that type parameters are well-formed.
mcimadamore@122: chk.validate(tree.typarams, localEnv);
duke@1:
duke@1: // Check that result type is well-formed.
mcimadamore@122: chk.validate(tree.restype, localEnv);
mcimadamore@629:
mcimadamore@629: // annotation method checks
mcimadamore@629: if ((owner.flags() & ANNOTATION) != 0) {
mcimadamore@629: // annotation method cannot have throws clause
mcimadamore@629: if (tree.thrown.nonEmpty()) {
mcimadamore@629: log.error(tree.thrown.head.pos(),
mcimadamore@629: "throws.not.allowed.in.intf.annotation");
mcimadamore@629: }
mcimadamore@629: // annotation method cannot declare type-parameters
mcimadamore@629: if (tree.typarams.nonEmpty()) {
mcimadamore@629: log.error(tree.typarams.head.pos(),
mcimadamore@629: "intf.annotation.members.cant.have.type.params");
mcimadamore@629: }
mcimadamore@629: // validate annotation method's return type (could be an annotation type)
duke@1: chk.validateAnnotationType(tree.restype);
mcimadamore@629: // ensure that annotation method does not clash with members of Object/Annotation
duke@1: chk.validateAnnotationMethod(tree.pos(), m);
duke@1:
mcimadamore@634: if (tree.defaultValue != null) {
mcimadamore@634: // if default value is an annotation, check it is a well-formed
mcimadamore@634: // annotation value (e.g. no duplicate values, no missing values, etc.)
mcimadamore@634: chk.validateAnnotationTree(tree.defaultValue);
mcimadamore@634: }
mcimadamore@629: }
mcimadamore@629:
duke@1: for (List l = tree.thrown; l.nonEmpty(); l = l.tail)
duke@1: chk.checkType(l.head.pos(), l.head.type, syms.throwableType);
duke@1:
duke@1: if (tree.body == null) {
duke@1: // Empty bodies are only allowed for
duke@1: // abstract, native, or interface methods, or for methods
duke@1: // in a retrofit signature class.
mcimadamore@1366: if (isDefaultMethod || ((owner.flags() & INTERFACE) == 0 &&
mcimadamore@1366: (tree.mods.flags & (ABSTRACT | NATIVE)) == 0) &&
duke@1: !relax)
duke@1: log.error(tree.pos(), "missing.meth.body.or.decl.abstract");
duke@1: if (tree.defaultValue != null) {
duke@1: if ((owner.flags() & ANNOTATION) == 0)
duke@1: log.error(tree.pos(),
duke@1: "default.allowed.in.intf.annotation.member");
duke@1: }
mcimadamore@1393: } else if ((tree.sym.flags() & ABSTRACT) != 0 && !isDefaultMethod) {
mcimadamore@1393: if ((owner.flags() & INTERFACE) != 0) {
mcimadamore@1393: log.error(tree.body.pos(), "intf.meth.cant.have.body");
mcimadamore@1393: } else {
mcimadamore@1393: log.error(tree.pos(), "abstract.meth.cant.have.body");
mcimadamore@1393: }
duke@1: } else if ((tree.mods.flags & NATIVE) != 0) {
duke@1: log.error(tree.pos(), "native.meth.cant.have.body");
duke@1: } else {
duke@1: // Add an implicit super() call unless an explicit call to
duke@1: // super(...) or this(...) is given
duke@1: // or we are compiling class java.lang.Object.
duke@1: if (tree.name == names.init && owner.type != syms.objectType) {
duke@1: JCBlock body = tree.body;
duke@1: if (body.stats.isEmpty() ||
duke@1: !TreeInfo.isSelfCall(body.stats.head)) {
duke@1: body.stats = body.stats.
duke@1: prepend(memberEnter.SuperCall(make.at(body.pos),
duke@1: List.nil(),
duke@1: List.nil(),
duke@1: false));
duke@1: } else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
duke@1: (tree.mods.flags & GENERATEDCONSTR) == 0 &&
duke@1: TreeInfo.isSuperCall(body.stats.head)) {
duke@1: // enum constructors are not allowed to call super
duke@1: // directly, so make sure there aren't any super calls
duke@1: // in enum constructors, except in the compiler
duke@1: // generated one.
duke@1: log.error(tree.body.stats.head.pos(),
duke@1: "call.to.super.not.allowed.in.enum.ctor",
duke@1: env.enclClass.sym);
duke@1: }
duke@1: }
duke@1:
duke@1: // Attribute method body.
duke@1: attribStat(tree.body, localEnv);
duke@1: }
duke@1: localEnv.info.scope.leave();
duke@1: result = tree.type = m.type;
duke@1: chk.validateAnnotations(tree.mods.annotations, m);
duke@1: }
duke@1: finally {
duke@1: chk.setLint(prevLint);
mcimadamore@795: chk.setMethod(prevMethod);
duke@1: }
duke@1: }
duke@1:
duke@1: public void visitVarDef(JCVariableDecl tree) {
duke@1: // Local variables have not been entered yet, so we need to do it now:
duke@1: if (env.info.scope.owner.kind == MTH) {
duke@1: if (tree.sym != null) {
duke@1: // parameters have already been entered
duke@1: env.info.scope.enter(tree.sym);
duke@1: } else {
duke@1: memberEnter.memberEnter(tree, env);
duke@1: annotate.flush();
duke@1: }
duke@1: }
duke@1:
duke@1: VarSymbol v = tree.sym;
jfranck@1313: Lint lint = env.info.lint.augment(v.annotations, v.flags());
duke@1: Lint prevLint = chk.setLint(lint);
duke@1:
mcimadamore@165: // Check that the variable's declared type is well-formed.
mcimadamore@165: chk.validate(tree.vartype, env);
mcimadamore@852: deferredLintHandler.flush(tree.pos());
mcimadamore@165:
duke@1: try {
duke@1: chk.checkDeprecatedAnnotation(tree.pos(), v);
duke@1:
duke@1: if (tree.init != null) {
mcimadamore@1348: if ((v.flags_field & FINAL) != 0 &&
mcimadamore@1348: !tree.init.hasTag(NEWCLASS) &&
mcimadamore@1352: !tree.init.hasTag(LAMBDA) &&
mcimadamore@1352: !tree.init.hasTag(REFERENCE)) {
duke@1: // In this case, `v' is final. Ensure that it's initializer is
duke@1: // evaluated.
duke@1: v.getConstValue(); // ensure initializer is evaluated
duke@1: } else {
duke@1: // Attribute initializer in a new environment
duke@1: // with the declared variable as owner.
duke@1: // Check that initializer conforms to variable's declared type.
duke@1: Env initEnv = memberEnter.initEnv(tree, env);
duke@1: initEnv.info.lint = lint;
duke@1: // In order to catch self-references, we set the variable's
duke@1: // declaration position to maximal possible value, effectively
duke@1: // marking the variable as undefined.
mcimadamore@94: initEnv.info.enclVar = v;
duke@1: attribExpr(tree.init, initEnv, v.type);
duke@1: }
duke@1: }
duke@1: result = tree.type = v.type;
duke@1: chk.validateAnnotations(tree.mods.annotations, v);
duke@1: }
duke@1: finally {
duke@1: chk.setLint(prevLint);
duke@1: }
duke@1: }
duke@1:
duke@1: public void visitSkip(JCSkip tree) {
duke@1: result = null;
duke@1: }
duke@1:
duke@1: public void visitBlock(JCBlock tree) {
duke@1: if (env.info.scope.owner.kind == TYP) {
duke@1: // Block is a static or instance initializer;
duke@1: // let the owner of the environment be a freshly
duke@1: // created BLOCK-method.
duke@1: Env localEnv =
duke@1: env.dup(tree, env.info.dup(env.info.scope.dupUnshared()));
duke@1: localEnv.info.scope.owner =
duke@1: new MethodSymbol(tree.flags | BLOCK, names.empty, null,
duke@1: env.info.scope.owner);
duke@1: if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
duke@1: attribStats(tree.stats, localEnv);
duke@1: } else {
duke@1: // Create a new local environment with a local scope.
duke@1: Env localEnv =
duke@1: env.dup(tree, env.info.dup(env.info.scope.dup()));
mcimadamore@1347: try {
mcimadamore@1347: attribStats(tree.stats, localEnv);
mcimadamore@1347: } finally {
mcimadamore@1347: localEnv.info.scope.leave();
mcimadamore@1347: }
duke@1: }
duke@1: result = null;
duke@1: }
duke@1:
duke@1: public void visitDoLoop(JCDoWhileLoop tree) {
duke@1: attribStat(tree.body, env.dup(tree));
duke@1: attribExpr(tree.cond, env, syms.booleanType);
duke@1: result = null;
duke@1: }
duke@1:
duke@1: public void visitWhileLoop(JCWhileLoop tree) {
duke@1: attribExpr(tree.cond, env, syms.booleanType);
duke@1: attribStat(tree.body, env.dup(tree));
duke@1: result = null;
duke@1: }
duke@1:
duke@1: public void visitForLoop(JCForLoop tree) {
duke@1: Env loopEnv =
duke@1: env.dup(env.tree, env.info.dup(env.info.scope.dup()));
mcimadamore@1347: try {
mcimadamore@1347: attribStats(tree.init, loopEnv);
mcimadamore@1347: if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
mcimadamore@1347: loopEnv.tree = tree; // before, we were not in loop!
mcimadamore@1347: attribStats(tree.step, loopEnv);
mcimadamore@1347: attribStat(tree.body, loopEnv);
mcimadamore@1347: result = null;
mcimadamore@1347: }
mcimadamore@1347: finally {
mcimadamore@1347: loopEnv.info.scope.leave();
mcimadamore@1347: }
duke@1: }
duke@1:
duke@1: public void visitForeachLoop(JCEnhancedForLoop tree) {
duke@1: Env loopEnv =
duke@1: env.dup(env.tree, env.info.dup(env.info.scope.dup()));
mcimadamore@1347: try {
mcimadamore@1347: attribStat(tree.var, loopEnv);
mcimadamore@1347: Type exprType = types.upperBound(attribExpr(tree.expr, loopEnv));
mcimadamore@1347: chk.checkNonVoid(tree.pos(), exprType);
mcimadamore@1347: Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
mcimadamore@1347: if (elemtype == null) {
mcimadamore@1347: // or perhaps expr implements Iterable?
mcimadamore@1347: Type base = types.asSuper(exprType, syms.iterableType.tsym);
mcimadamore@1347: if (base == null) {
mcimadamore@1347: log.error(tree.expr.pos(),
mcimadamore@1347: "foreach.not.applicable.to.type",
mcimadamore@1347: exprType,
mcimadamore@1347: diags.fragment("type.req.array.or.iterable"));
mcimadamore@1347: elemtype = types.createErrorType(exprType);
mcimadamore@1347: } else {
mcimadamore@1347: List iterableParams = base.allparams();
mcimadamore@1347: elemtype = iterableParams.isEmpty()
mcimadamore@1347: ? syms.objectType
mcimadamore@1347: : types.upperBound(iterableParams.head);
mcimadamore@1347: }
duke@1: }
mcimadamore@1347: chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
mcimadamore@1347: loopEnv.tree = tree; // before, we were not in loop!
mcimadamore@1347: attribStat(tree.body, loopEnv);
mcimadamore@1347: result = null;
duke@1: }
mcimadamore@1347: finally {
mcimadamore@1347: loopEnv.info.scope.leave();
mcimadamore@1347: }
duke@1: }
duke@1:
duke@1: public void visitLabelled(JCLabeledStatement tree) {
duke@1: // Check that label is not used in an enclosing statement
duke@1: Env env1 = env;
jjg@1127: while (env1 != null && !env1.tree.hasTag(CLASSDEF)) {
jjg@1127: if (env1.tree.hasTag(LABELLED) &&
duke@1: ((JCLabeledStatement) env1.tree).label == tree.label) {
duke@1: log.error(tree.pos(), "label.already.in.use",
duke@1: tree.label);
duke@1: break;
duke@1: }
duke@1: env1 = env1.next;
duke@1: }
duke@1:
duke@1: attribStat(tree.body, env.dup(tree));
duke@1: result = null;
duke@1: }
duke@1:
duke@1: public void visitSwitch(JCSwitch tree) {
duke@1: Type seltype = attribExpr(tree.selector, env);
duke@1:
duke@1: Env switchEnv =
duke@1: env.dup(tree, env.info.dup(env.info.scope.dup()));
duke@1:
mcimadamore@1347: try {
mcimadamore@1347:
mcimadamore@1347: boolean enumSwitch =
mcimadamore@1347: allowEnums &&
mcimadamore@1347: (seltype.tsym.flags() & Flags.ENUM) != 0;
mcimadamore@1347: boolean stringSwitch = false;
mcimadamore@1347: if (types.isSameType(seltype, syms.stringType)) {
mcimadamore@1347: if (allowStringsInSwitch) {
mcimadamore@1347: stringSwitch = true;
mcimadamore@1347: } else {
mcimadamore@1347: log.error(tree.selector.pos(), "string.switch.not.supported.in.source", sourceName);
mcimadamore@1347: }
darcy@430: }
mcimadamore@1347: if (!enumSwitch && !stringSwitch)
mcimadamore@1347: seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
mcimadamore@1347:
mcimadamore@1347: // Attribute all cases and
mcimadamore@1347: // check that there are no duplicate case labels or default clauses.
mcimadamore@1347: Set