Bug 12387 - Out Of Memory error importing file
Summary: Out Of Memory error importing file
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows NT
: P2 normal (vote)
Target Milestone: 2.0 M5   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-03-27 15:47 EST by David Wegener CLA
Modified: 2002-03-28 09:32 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description David Wegener CLA 2002-03-27 15:47:24 EST
Build 20020321 stable
Importing the file below causes an Out of Memory error in eclipse.  Here is the 
log file:
Log: Wed Mar 27 14:38:33 CST 2002
1 org.eclipse.core.resources 4 Unhandled exception caught in event loop.
Log: Wed Mar 27 14:38:33 CST 2002
4 org.eclipse.ui 0 java.lang.OutOfMemoryError
java.lang.OutOfMemoryError
	<<no stack trace available>>

Problem seems to be associated with parsing the file.  If I turn auto build 
off, the error doesn't appear until I expand the package in the packages view.  
If I turn off Show Members in Packages View it doesn't appear until I open the 
file in the Java editor.  The file is part of the Dr Java package from Rice 
university (http://drjava.sourceforge.net/).  It appears to be compiled with a 
generics compliant compiler as the extends clause contains the following: 
extends Tree.Visitor<Type,Env<AttrContext>>.

As this is not valid Java, I wouldn't expect this to compile.  However, the out 
of memory error could possibly be avoided.  I am able to recreate the problem 
by having autobuild turned on and importing the file into an existing project.



/* ************************************************************************
 * GJC attribution phase
 * by Martin Odersky
 *
 * Copyright (C) 1996-98 Martin Odersky. All rights reserved.
 * Permission is hereby granted to use and modify this software for evaluation
 * and research purposes. Modification and use for other purposes requires
 * prior written permission by the author. The software, or modifications
 * thereof may be given to third parties only with prior written permission
 * by the author.
 *************************************************************************/

package edu.rice.cs.nextgen.compiler.comp;

import edu.rice.cs.nextgen.compiler.util.*;
import edu.rice.cs.nextgen.compiler.code.*;
import edu.rice.cs.nextgen.compiler.tree.*;

import Symbol.*;
import Tree.*;
import Type.*;

public class Attr
extends Tree.Visitor<Type,Env<AttrContext>>
implements /* imports */ Flags, Kinds, TypeTags {

    Log log;
    Symtab syms;
    Resolve rs;
    Check chk;
    Infer infer;
    TreeMaker make;
    public Enter enter;
    public ConstFold cfolder;

    public Attr(Log log, Symtab syms,
		Resolve rs, Check chk, Infer infer,
		TreeMaker make, Enter enter) {
	this.log = log;
	this.syms = syms;
	this.rs = rs;
	this.chk = chk;
	this.infer = infer;
	this.make = make;
	this.enter = enter;
	if (enter != null) enter.attr = this;
	this.cfolder = new ConstFold(log, syms);
    }

    /** check kind and type of given tree against prototype
     *  store resulting type to tree and return it.
     *  no checks are performed if the prototype is a method type.
     *  Its not necessary in this case since we know that kind and type
     *  are correct.
     */
    Type check(Tree tree, Type owntype, int ownkind, int pkind, Type pt) {
	if (owntype.tag != ERROR && pt.tag != METHOD) {
	    if ((ownkind & ~pkind) == 0) {
		if (pt.tag != NONE)
		    owntype = chk.checkType(tree.pos, owntype, pt);
	    } else {
		log.error(tree.pos,
			  Resolve.kindNames(pkind) + " required, but " +
			  Resolve.kindName(ownkind) + " found");
		owntype = Type.errType;
	    }
	}
	tree.type = owntype;
	return owntype;
    }

    /** is variable `v' assignable, i.e. in a scope where it may be assigned to
     *  even if it is final?
     */
    static boolean finalAssignable(VarSymbol v, Env<AttrContext> env) {
	Symbol owner = env.info.scope.owner;
	return
	    v.constValue == null
	    &&
	    (v.owner == owner
	     ||
	     ((owner.name == Names.init || (owner.flags() & BLOCK) != 0)
	      &&
	      v.owner == owner.owner
	      &&
	      ((v.flags() & STATIC) != 0) == (Resolve.isStatic(env))));
    }

    /** check that variable `v' can be assigned to.
     */
    void checkAssignable(int pos, VarSymbol v, Tree base, Env<AttrContext> env) 
{
	if ((v.flags() & FINAL) != 0 &&
	    !((base == null ||
	       (base.tag == Tree.IDENT && TreeInfo.name(base) == Names._this)) 
&&
	      finalAssignable(v, env))) {
	    log.error(pos, "can't assign a value to final " + v);
	}
    }

    /** warn about deprecated symbol if not in currently ccompiled files
     */
    void warnDeprecated(int pos, Symbol sym) {
	if (!enter.compiled.contains(sym.enclClass().fullname))
	    log.warning(pos, sym + sym.location() + " has been deprecated");
    }

    /** the current `this' symbol
     */
    Symbol thisSym(Env<AttrContext> env) {
	return rs.resolveSelf(
	    Position.NOPOS, env, env.enclClass.sym, Names._this);
    }

    /** if `site' is an inner class, prepend outer instance to argtypes
     *  outer instance is taken to be `outer' if not null, is made up otherwise.
     */
    List<Type> constructorArgs(int pos, Env<AttrContext> env,
			       Type site, Type outer, List<Type> argtypes) {
	if (site.outer().tag == CLASS) {
	    if (outer == null) {
		Symbol outerthis = rs.resolveSelf(
		    pos, env, site.outer().tsym, Names._this);
		if (outerthis.kind == VAR) {
/*//todo: revise this
		    if (env.info.isSelfCall &&
			outerthis.owner == env.enclClass.sym)
			chk.earlyRefError(pos, outerthis);
 */
		    outer = outerthis.owner.type;
		} else {
		    outer = Type.errType;
		}
	    }
	    argtypes = argtypes.prepend(outer);
	} else if (outer != null && outer.tag == CLASS && site.tag != ERROR) {
	    log.error(pos,
		"illegal qualifier; " + site.tsym + " is not an inner class");
	}
	return argtypes;
    }

    Type attribTerm(Tree tree, Env<AttrContext> env, int pkind, Type pt) {
	try {
	    env.info.pkind = pkind;
	    env.info.pt = pt;
	    return tree.visit(this, env);
	} catch (CompletionFailure ex) {
	    return chk.completionError(tree.pos, ex);
	}
    }	

    Type attribExpr(Tree tree, Env<AttrContext> env, Type pt) {
	return attribTerm(tree, env, VAL, pt);
    }

    Type attribExpr(Tree tree, Env<AttrContext> env) {
	return attribExpr(tree, env, Type.noType);
    }

    Type attribType(Tree tree, Env<AttrContext> env) {
	return attribTerm(tree, env, TYP, Type.noType);
    }

    Type attribStat(Tree tree, Env<AttrContext> env) {
	return attribTerm(tree, env, NIL, Type.noType);
    }

    List<Type> attribExprs(List<Tree> trees, Env<AttrContext> env, Type pt) {
	ListBuffer<Type> ts = new ListBuffer<Type>();
	for (List<Tree> l = trees; l.nonEmpty(); l = l.tail)
	    ts.append(attribExpr(l.head, env, pt));
	return ts.toList();
    }

    <T extends Tree> void attribStats(List<T> trees, Env<AttrContext> env) {
	for (List<T> l = trees; l.nonEmpty(); l = l.tail)
	    attribStat(l.head, env);
    }

    List<Type> attribArgs(List<Tree> trees, Env<AttrContext> env) {
	ListBuffer<Type> argtypes = new ListBuffer<Type>();
	for (List<Tree> l = trees; l.nonEmpty(); l = l.tail)
	    argtypes.append(chk.checkNonVoid(
		l.head.pos, attribExpr(l.head, env)));
	return argtypes.toList();
    }

    /** attribute extended or implemented type reference
     */
    Type attribBase(Tree tree, Env<AttrContext> env, int interfaceFlag) {
	Type t = chk.checkClassType(tree.pos, attribType(tree, env));
	if ((t.tsym.flags() & INTERFACE) != interfaceFlag) {
	    log.error(tree.pos,
		(interfaceFlag == 0 ? "no " : "") + "interface expected here");
	}
	if ((t.tsym.flags() & FINAL) != 0) {
	    log.error(tree.pos, "can't inherit from final " + t.tsym);
	}
	return t;
    }

/* ********************************************************************
 * Adding miranda methods
 *********************************************************************/

    /** add an abstract method definition to class definition `cd'
     *  for a method `m' defined in an interface
     */
    private void addAbstractMethod(ClassDef cd,
				   MethodSymbol m,
				   Env<AttrContext> env) {
//	System.err.println("add abstract method: " + m);//DEBUG
	Tree def = make.at(cd.pos).MethodDef(
	    new MethodSymbol(
		m.flags() | IPROXY, m.name, cd.sym.type.memberType(m), cd.sym),
	    null);
	cd.defs = cd.defs.prepend(def);
	enter.memberEnter(def, env);
    }

    /** add abstract method definitions for all methods defined in one of
     *  c's interfaces, provided they are not already implemented
     *  env = the environment for the class definition of c.
     */
    void implementInterfaceMethods(ClassSymbol c, Env<AttrContext> env) {
	ClassDef cd = (ClassDef)env.tree;
	for (List<Type> l = c.type.interfaces(); l.nonEmpty(); l = l.tail) {
	    ClassSymbol i = (ClassSymbol)l.head.tsym;
	    for (Scope.Entry e = i.members().elems;
		 e != null;
		 e = e.sibling) {
		if (e.sym.kind == MTH &&
		    (e.sym.flags() & STATIC) == 0) // disregard <clinit>!
		{
		    MethodSymbol absMeth = (MethodSymbol)e.sym;
		    MethodSymbol implMeth = absMeth.implementation(cd.sym);
		    if (implMeth == null)
			addAbstractMethod(cd, absMeth, env);
		}
	    }
	    implementInterfaceMethods(i, env);
	}
    }

/* ************************************************************************
 * visitor methods
 *************************************************************************/

    public Type _case(ClassDef tree, Env<AttrContext> env) {
	if ((env.info.scope.owner.kind & (VAR | MTH)) != 0) {
	    enter.classEnter(tree, env);
	} else if (tree.name.len == 0) {
	    System.out.println(env.info.scope.owner);
	}
	ClassSymbol c = tree.sym;
	if (c == null) return null;
	c.complete();
	attribClass(c);
	return tree.type = c.type;
    }

    public Type _case(MethodDef tree, Env<AttrContext> env) {
	MethodSymbol m = tree.sym;
	chk.checkOverride(tree.pos, m);

	Env<AttrContext> localEnv = enter.methodEnv((MethodDef)tree, env);
	for (List<TypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
	    localEnv.info.scope.enterIfAbsent(l.head.type.tsym);
	for (List<VarDef> l = tree.params; l.nonEmpty(); l = l.tail)
	    attribStat(l.head, localEnv);

	chk.validateTypeParams(tree.typarams);
	chk.validate(tree.restype);
	for (List<Tree> l = tree.thrown; l.nonEmpty(); l = l.tail)
	    chk.checkType(l.head.pos, l.head.type, syms.throwableType);
	
	ClassSymbol owner = env.enclClass.sym;
	if (tree.body == null) {
	    if ((owner.flags() & INTERFACE) == 0 &&
		(tree.flags & (ABSTRACT | NATIVE)) == 0)
		log.error(tree.pos,
			  "missing method body, or declare as abstract");
	} else if ((owner.flags() & INTERFACE) != 0) {
	    log.error(tree.pos, "interface methods cannot have body");
	} else if ((tree.flags & ABSTRACT) != 0) {
	    log.error(tree.pos, "abstract methods cannot have body");
	} else if ((tree.flags & NATIVE) != 0) {
	    log.error(tree.pos, "native methods cannot have body");
	} else {
	    if (tree.name == Names.init && owner.type != syms.objectType) {
		Block body = tree.body;
		if (body.stats.isEmpty() || !isSelfCall(body.stats.head)) {
		    body.stats = body.stats.prepend(
			Enter.SuperCall(
			    make.at(body.pos), VarDef.emptyList, false));
		}
	    }
	    attribStat(tree.body, localEnv);
	}
	localEnv.info.scope.leave();
	return tree.type = m.type;
    }
//where
        private boolean isSelfCall(Tree tree) {
	    if (tree.tag == Tree.EXEC) {
		Exec exec = (Exec)tree;
		if (exec.expr.tag == Tree.APPLY) {
		    Name mname = TreeInfo.name(((Apply)exec.expr).meth);
		    if (mname == Names._this || mname == Names._super) return 
true;
		}
	    }
	    return false;
	}

    public Type _case(VarDef tree, Env<AttrContext> env) {
	if (env.info.scope.owner.kind == MTH) enter.memberEnter(tree, env);
	chk.validate(tree.vartype);
	VarSymbol v = tree.sym;
	Base.assert(v != null, tree.name);
	if (tree.init != null) {
	    v.pos = Position.MAXPOS; //to catch self references
	    Type itype = attribExpr(
		tree.init, enter.initEnv((VarDef)tree, env), v.type);
	    if (v.constValue instanceof Enter.EnvAttrContextBox) {
		if (itype.constValue != null)
		    v.constValue = cfolder.coerce(itype, v.type).constValue;
		else
		    v.constValue = null;
	    }
	    v.pos = tree.pos;
	}
	return tree.type = v.type;
    }

    public Type _case(Block tree, Env<AttrContext> env) {
	Env<AttrContext> localEnv =
	    env.dup(tree, env.info.dup(env.info.scope.dup()));
	if (env.info.scope.owner.kind == TYP) {
	    localEnv.info.scope.owner = new MethodSymbol(
		tree.flags | BLOCK, Names.empty, null, env.info.scope.owner);
	    if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
	}
	attribStats(tree.stats, localEnv);
	localEnv.info.scope.leave();
	return null;
    }

    public Type _case(DoLoop tree, Env<AttrContext> env) {
	attribStat(tree.body, env.dup(tree));
	attribExpr(tree.cond, env, Type.booleanType);
	return null;
    }

    public Type _case(WhileLoop tree, Env<AttrContext> env) {
	attribExpr(tree.cond, env, Type.booleanType);
	attribStat(tree.body, env.dup(tree));
	return null;
    }

    public Type _case(ForLoop tree, Env<AttrContext> env) {
	Env<AttrContext> loopEnv =
	    env.dup(env.tree, env.info.dup(env.info.scope.dup()));
	attribStats(tree.init, loopEnv);
	if (tree.cond != null) attribExpr(tree.cond, loopEnv, Type.booleanType);
	loopEnv.tree = tree; // before, we were not in loop!
	attribStats(tree.step, loopEnv);
	attribStat(tree.body, loopEnv);
	loopEnv.info.scope.leave();
	return null;
    }

    public Type _case(Labelled tree, Env<AttrContext> env) {
	attribStat(tree.body, env.dup(tree));
	return null;
    }

    public Type _case(Switch tree, Env<AttrContext> env) {
	Type seltype = attribExpr(tree.selector, env, Type.intType);
	Env<AttrContext> switchEnv =
	    env.dup(tree, env.info.dup(env.info.scope.dup()));

	Set<Object> tags = Set.make();
	boolean hasDefault = false;
	for (List<Case> l = tree.cases; l.nonEmpty(); l = l.tail) {
	    Case c = l.head;
	    if (c.pat != null) {
		Type pattype = attribExpr(c.pat, switchEnv, Type.intType);
		if (pattype.tag != ERROR) {
		    if (pattype.constValue == null)
			log.error(c.pat.pos, "constant expression required");
		    else if (tags.contains(pattype.constValue))
			log.error(c.pos, "duplicate case label");
		    else
			tags.put(pattype.constValue);
		}
	    } else if (hasDefault) {
		log.error(c.pos, "duplicate default label");
	    } else {
		hasDefault = true;
	    }
	    attribStats(c.stats, switchEnv);
	}
	switchEnv.info.scope.leave();
	return null;
    }

    public Type _case(Synchronized tree, Env<AttrContext> env) {
	attribExpr(tree.lock, env, syms.objectType);
	attribStat(tree.body, env);
	return null;
    }

    public Type _case(Try tree, Env<AttrContext> env) {
	Env<AttrContext> tryEnv = env.dup(tree, env.info.dup());
	for (List<Catch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
	    Catch c = l.head;
	    Env<AttrContext> catchEnv =
		env.dup(c, env.info.dup(env.info.scope.dup()));
	    Type ctype = attribStat(c.param, catchEnv);
	    chk.checkType(c.param.vartype.pos, ctype, syms.throwableType);
	    attribStat(c.body, catchEnv);
	    ClassSymbol exc = (ClassSymbol)ctype.tsym;
	    catchEnv.info.scope.leave();
	}
	attribStat(tree.body, tryEnv);
	if (tree.finalizer != null) attribStat(tree.finalizer, env);
	return null;
    }

    public Type _case(Conditional tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	attribExpr(tree.cond, env, Type.booleanType);
	attribExpr(tree.thenpart, env, pt);
	if (tree.elsepart != null) attribExpr(tree.elsepart, env, pt);
	if (tree.tag == Tree.CONDSTAT)
	    return null;
	else
	    return check(
		tree,
		condType(
		    tree.pos,
		    tree.cond.type, tree.thenpart.type, tree.elsepart.type),
		VAL, pkind, pt);
    }
//where
        private Type condType(int pos, Type condtype, Type thentype, Type 
elsetype) {
	    if (condtype.constValue != null &&
		thentype.constValue != null &&
		elsetype.constValue != null)
		return (((Number)condtype.constValue).intValue() != 0)
		    ? thentype
		    : elsetype;
	    else if (thentype.tag < INT && elsetype.tag == INT &&
		elsetype.assignable(thentype))
		return thentype;
	    else if (elsetype.tag < INT && thentype.tag == INT &&
		     thentype.assignable(elsetype))
		return elsetype;
	    else if (thentype.tag <= DOUBLE && elsetype.tag <= DOUBLE) {
		for (int i = BYTE; i <= DOUBLE; i++) {
		    Type candidate = Type.typeOfTag[i];
		    if (thentype.subType(candidate) &&
			elsetype.subType(candidate)) return candidate;
		}
	    }
	    if (thentype.tsym == syms.stringType.tsym &&
		elsetype.tsym == syms.stringType.tsym) {
		return syms.stringType;
	    } else if (thentype.subType(elsetype)) {
		return elsetype;
	    } else {
		chk.checkType(pos, elsetype, thentype);
		return thentype;
	    }
	}

    public Type _case(Exec tree, Env<AttrContext> env) {
	attribExpr(tree.expr, env);
	return null;
    }

    public Type _case(Break tree, Env<AttrContext> env) {
	tree.target = findJumpTarget(tree.pos, tree.tag, tree.label, env);
	return null;
    }

    public Type _case(Continue tree, Env<AttrContext> env) {
	tree.target = findJumpTarget(tree.pos, tree.tag, tree.label, env);
	return null;
    }
//where
        private Tree findJumpTarget(int pos,
				    int tag,
				    Name label,
				    Env<AttrContext> env) {
	    Env<AttrContext> env1 = env;
	    while (env1 != null) {
		switch (env1.tree.tag) {
		case Tree.LABELLED:
		    Labelled labelled = (Labelled)env1.tree;
		    if (label == labelled.label) {
			Tree target = labelled.body;
			while (target.tag == Tree.LABELLED) {
			    target = ((Labelled)target).body;
			}
			if (tag == Tree.CONTINUE &&
			    target.tag != Tree.DOLOOP &&
			    target.tag != Tree.WHILELOOP &&
			    target.tag != Tree.FORLOOP)
			    log.error(pos, "not a loop label: " + label);
			return target;
		    }
		    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;
		default:
		}
		env1 = env1.next;
	    }
	    if (label != null)
		log.error(pos, "undefined label: " + label);
	    else if (tag == Tree.CONTINUE)
		log.error(pos, "continue outside of loop");
	    else
		log.error(pos, "break outside switch or loop");
	    return null;
	}

    public Type _case(Return tree, Env<AttrContext> env) {
	if (env.enclMethod == null ||
	    env.enclClass.sym.owner == env.enclMethod.sym) {
	    log.error(tree.pos, "return outside method");
	} else {
	    Symbol m = env.enclMethod.sym;
	    if (m.type.restype().tag == VOID) {
		if (tree.expr != null)
		    log.error(
			tree.expr.pos, "can't return a value from method " +
			"whose result type is void");
	    } else if (tree.expr == null) {
		log.error(tree.pos, "missing return value");
	    } else {
		attribExpr(tree.expr, env, m.type.restype());
	    }
	}
	return null;
    }

    public Type _case(Throw tree, Env<AttrContext> env) {
	Type t = attribExpr(tree.expr, env, syms.throwableType);
	return null;
    }

    public Type _case(Apply tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type owntype = Type.errType;
	Env<AttrContext> localEnv = env;
	List<Type> argtypes;
	Name methName = TreeInfo.name(tree.meth);
	boolean isConstructorCall =
	    methName == Names._this || methName == Names._super;
	if (isConstructorCall && checkFirstConstructorStat(tree, env)) {
	    localEnv = env.dup(env.tree, env.info.dup());
	    localEnv.info.isSelfCall = true;
	    argtypes = attribArgs(tree.args, localEnv);
	    Type site = env.enclClass.sym.type;
	    if (methName == Names._super) site = site.supertype();
	    Type encltype = (tree.meth.tag == Tree.SELECT)
		? attribExpr(((Select)tree.meth).selected, env)
		: null;
	    argtypes = constructorArgs(
		tree.meth.pos, localEnv, site, encltype, argtypes);
	} else {
	    argtypes = attribArgs(tree.args, localEnv);
	}

	List<MethodType> saved = methTemplateSupply.elems;
	Type mpt = newMethTemplate(argtypes);
	// optimization, was ... = new MethodType(argtypes, null, null);

	owntype = attribExpr(tree.meth, localEnv, mpt);

	methTemplateSupply.elems = saved; // optimization

	if (isConstructorCall) {
	    Symbol called = TreeInfo.symbol(tree.meth);
	    if (called == env.enclMethod.sym)
		log.error(tree.pos, "recursive constructor invocation");
//todo: handle indirect recursion as well
	}
	return check(tree, owntype, VAL, pkind, pt);
    }
//where
        private boolean checkFirstConstructorStat(Apply tree, Env<AttrContext> 
env) {
	    MethodDef enclMethod = env.enclMethod;
	    if (enclMethod != null && enclMethod.name == Names.init) {
		Block body = (Block)enclMethod.body;
		if (body.stats.head.tag == Tree.EXEC &&
		    ((Exec)body.stats.head).expr == tree)
		    return true;
	    }
	    log.error(tree.pos, "call to " + TreeInfo.name(tree.meth) +
		      " must be first statement in constructor");
	    return false;
	}

        /** optimization: To save allocating a new methodtype for every apply,
	 *  we use a reservoir.
	 */
        ListBuffer<MethodType> methTemplateSupply = new ListBuffer<MethodType>
();

        public Type newMethTemplate(List<Type> argtypes) {
	    if (methTemplateSupply.elems == methTemplateSupply.last)
		methTemplateSupply.append(new MethodType(null, null, null));
	    MethodType mt = methTemplateSupply.elems.head;
	    methTemplateSupply.elems = methTemplateSupply.elems.tail;
	    mt.argtypes = argtypes;
	    return mt;
	}

    public Type _case(NewClass tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type owntype = Type.errType;
	ClassDef cdef = tree.def;

	// if enclosing class is given, attribute it, and
	// complete class name to be fully qualified
	Type encltype = null;
	Tree clazz = tree.clazz;
	if (tree.encl != null) {
	    encltype = attribExpr(tree.encl, env);
	    if (encltype.tag == CLASS) {
		clazz = make.at(clazz.pos).Select(
		    make.Type(encltype), ((Ident)tree.clazz).name);
//		new Pretty().printExpr(clazz);//DEBUG
	    }
	}

	// attribute clazz and store symbol + type back into tree
	Type clazztype = chk.checkClassType(
	    tree.clazz.pos, attribType(clazz, env));
	chk.validate(clazz);	
	if (tree.encl != null) {
	    tree.clazz.type = clazztype;
	    ((Ident)tree.clazz).sym = TreeInfo.symbol(clazz);
	}

	// attribute arguments;
	List<Type> rawArgtypes = attribArgs(tree.args, env);
	List<Type> argtypes = rawArgtypes;

	if (clazztype.tag == CLASS) {
	    Type site = clazztype.tsym.type;
	    List<Type> typarams = clazztype.typarams();

	    // resolve constructor, if not abstract
	    if (cdef == null &&
		(clazztype.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
		log.error(tree.pos,
		    clazztype.tsym + " is abstract; cannot be instantiated");
	    } else if (cdef != null &&
		       (clazztype.tsym.flags() & INTERFACE) != 0) {
		if (rawArgtypes.nonEmpty()) {
		    log.error(tree.pos,
			      "anonymous class implements interface; " +
			      "cannot have arguments");
		    rawArgtypes = argtypes = Type.emptyList;
		} else if (tree.encl != null) {
		    log.error(tree.pos,
			      "anonymous class implements interface; " +
			      "cannot have qualifier for new");
		}
	    } else {
		argtypes = constructorArgs(
		    tree.pos, env, site, encltype, rawArgtypes);
		boolean selectSuperPrev = env.info.selectSuper;
		if (cdef != null) env.info.selectSuper = true;
		tree.constructor = rs.resolveConstructor(
		    tree.pos, env, site, typarams, argtypes);
		env.info.selectSuper = selectSuperPrev;
	    }

	    // if it's an anonymous class...
	    if (cdef != null) {

		// complete class definition with extends/implements clause
	        // and enter + attribute it.
		if (Resolve.isStatic(env)) cdef.flags |= STATIC;

		Tree clazz1 = make.at(cdef.pos).Type(clazztype);
		if ((clazztype.tsym.flags() & INTERFACE) != 0) {
		    cdef.implementing = List.make(clazz1);
		} else {
		    cdef.extending = clazz1;
		}
		attribStat(cdef, env.dup(tree));
//	        new Pretty().printStat(cdef);//DEBUG

		// if enclosing class is given,
		// add it to constructor arguments
		if (tree.encl != null) {
		    tree.args = tree.args.prepend(tree.encl);
		    rawArgtypes = rawArgtypes.prepend(encltype);
		    tree.encl = null;
		    encltype = null;
		}

		// reassign site, typarams and recompute constructor
		site = cdef.sym.type;
		typarams = Type.emptyList;
		argtypes = constructorArgs(
		    tree.pos, env, site, encltype, rawArgtypes);
		tree.constructor = rs.resolveConstructor(
		    tree.pos, env, site, typarams, argtypes);
	    }
	    if (tree.constructor != null && tree.constructor.kind == MTH) {
		owntype = rs.instantiate(
		    site, tree.constructor, typarams, argtypes);
		if (owntype == null) {//debug
		    log.error(
			tree.pos, "internal error; cannot instantiate " +
			tree.constructor + " to (" + argtypes + ")");
		}
	    }
	}
	return check(tree, owntype, VAL, pkind, pt);
    }

    public Type _case(NewArray tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type owntype = Type.errType;
	Type elemtype;
	if (tree.elemtype != null) {
	    elemtype = attribType(tree.elemtype, env);
	    if (elemtype.tag == TYPEVAR) {
		log.warning(tree.pos, "unchecked generic array creation");
	    }
	    chk.validate(tree.elemtype);
	    owntype = elemtype;
	    for (List<Tree> l = tree.dims; l.nonEmpty(); l = l.tail) {
		attribExpr(l.head, env, Type.intType);
		owntype = new ArrayType(owntype);
	    }
	} else {
	    if (pt.tag == ARRAY) {
		elemtype = pt.elemtype();
	    } else {
		if (pt.tag != ERROR) {
		    log.error(tree.pos, "illegal initializer for " + pt);
		}
		elemtype = Type.errType;
	    }
	}
	if (tree.elems != null) {
	    attribExprs(tree.elems, env, elemtype);
	    owntype = new ArrayType(elemtype);
	}
	return check(tree, owntype, VAL, pkind, pt);
    }

    public Type _case(Assign tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type owntype = attribTerm(tree.lhs, env.dup(tree), VAR, pt);
	attribExpr(tree.rhs, env, owntype);
	return check(tree, owntype, VAL, pkind, pt);
    }

    public Type _case(Assignop tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	List<Type> argtypes = List.make(
	    attribTerm(tree.lhs, env, VAR, Type.noType),
	    attribExpr(tree.rhs, env));
	Symbol operator = tree.operator = rs.resolveOperator(
	    tree.pos, tree.tag - Tree.ASGOffset, env, argtypes);
	Type owntype = argtypes.head;
	if (operator.kind == MTH) {
	    if (owntype.tag <= DOUBLE)
		chk.checkCastable(
		    tree.rhs.pos, operator.type.restype(), owntype);
	    else
		chk.checkType(
		    tree.rhs.pos, operator.type.restype(), owntype);
	}
	return check(tree, owntype, VAL, pkind, pt);
    }

    public Type _case(Operation tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	List<Type> argtypes;
	if (Tree.PREINC <= tree.tag && tree.tag <= Tree.POSTDEC)
	    argtypes = Type.emptyList.prepend(
		attribTerm(tree.args.head, env, VAR, Type.noType));
	else
	    argtypes = attribArgs(tree.args, env);
	Symbol operator = tree.operator = rs.resolveOperator(
	    tree.pos, tree.tag, env, argtypes);
	Type owntype = Type.errType;
	if (operator.kind == MTH) {
	    owntype = operator.type.restype();
	    int opc = ((OperatorSymbol)operator).opcode;
	    List<Type> l = argtypes;
	    while (l.nonEmpty() && l.head.constValue != null) l = l.tail;
	    if (l.isEmpty()) {
		Type ctype = cfolder.fold(tree.pos, opc, argtypes);
		if (ctype != null) owntype = cfolder.coerce(ctype, owntype);
	    }
	    if ((opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne) &&
		!argtypes.head.castableTo(argtypes.tail.head.erasure()) &&
		!argtypes.tail.head.castableTo(argtypes.head.erasure())) {
		log.error(
		    tree.pos, "incomparable types: " +
		    argtypes.head + " and " + argtypes.tail.head);
	    }
	}
	return check(tree, owntype, VAL, pkind, pt);
    }

    public Type _case(TypeCast tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type clazztype = attribType(tree.clazz, env);
	Type exprtype = attribExpr(tree.expr, env);
	Type owntype = chk.checkCastable(tree.expr.pos, exprtype, clazztype);
	if (exprtype.constValue != null)
	    owntype = cfolder.coerce(exprtype, owntype);
	return check(tree, owntype, VAL, pkind, pt);
    }

    public Type _case(TypeTest tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type exprtype = attribExpr(tree.expr, env);

        // The following check is correct for GJ but not for NextGen  Corky 
6/28/00
	/* Type clazztype = chk.checkClassOrArrayType(
	   tree.clazz.pos, attribType(tree.clazz, env)); */
        // In the following invocation, attribType(tree.clazz,env) replaces 
clazztype, which is consistent with successful return from checkClassOrArrayType
	chk.checkCastable(tree.expr.pos, exprtype, attribType
(tree.clazz,env));  
	return check(tree, Type.booleanType, VAL, pkind, pt);
    }

    public Type _case(Indexed tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type owntype = Type.errType;
	Type atype = attribExpr(tree.indexed, env);
	attribExpr(tree.index, env, Type.intType);
	if (atype.tag == ARRAY)
	    owntype = atype.elemtype();
	else if (atype.tag != ERROR)
	    log.error(tree.pos, "array required, but " + atype + " found");
	return check(tree, owntype, VAR, pkind, pt);
    }

    public Type _case(Ident tree, Env<AttrContext> env) {
	int pkind = env.info.pkind;
	Type pt = env.info.pt;
	Symbol sym;
	
	// find symbol
	if (pt.tag == METHOD) {
	    if (tree.name == Names._super || tree.name == Names._this) {
		sym = rs.resolveSelfConstructor(
		    tree.pos, env, tree.name, pt.argtypes());
	    } else {
		sym = rs.resolveMethod(
		    tree.pos, env, tree.name, Type.emptyList, pt.argtypes());
	    }
	} else {
	    sym = rs.resolveIdent(tree.pos, env, tree.name, pkind);
	}
	tree.sym = sym;

	//check that symbol does not hide identifier in outer class
	if (env.enclClass.sym.owner.kind != PCK &&
	    (sym.kind & (VAR | MTH)) != 0 && 	
	    sym.owner.kind == TYP &&
	    tree.name != Names._super && tree.name != Names._this) {
	    Env<AttrContext> env1 = env;
	    while (env1.outer != null && !env1.enclClass.sym.subclass
(sym.owner))
		env1 = env1.outer;
	    if (env1 != null && env1.enclClass.sym != sym.owner) {
		do {
		    env1 = env1.outer;
		} while (env1 != null &&
		       (env1.info.scope == null ||
			checkNotHiding(tree.pos, sym, env1.info.scope)) &&
		       (env1.enclClass == null ||
			checkNotHiding(tree.pos, sym, env1.enclClass.sym.members
())));
	    }
	}
		
	// if symbol is a variable, evaluate its initializer, if it has one
	// if it is a local variable accessed from an embedded inner class,
	// mark it as captured, and check that it is final.
	if (sym.kind == VAR) {
	    VarSymbol v = (VarSymbol)sym;
	    checkInit(tree, env, v);
	    if (v.owner.kind == MTH &&
		v.owner != env.info.scope.owner &&
		(v.flags_field & CAPTURED) == 0) {
		v.flags_field |= CAPTURED;
		if ((v.flags_field & FINAL) == 0) {
		    log.error(
			tree.pos, "local " + v +
			" is accessed from within inner class; " +
			" needs to be declared final");
		}
	    }
	    if (pkind == VAR)
		checkAssignable(tree.pos, v, null, env);
	}

	// in constructor body:
        // if symbol is a field or instance method, check that it is not 
accessed
        // before supertype constructor is called.
	if (env.info.isSelfCall &&
	    sym.owner != null && sym.owner.kind == TYP &&
	    (sym.flags() & STATIC) == 0 &&
	    env.enclClass.sym.subclass(sym.owner) &&
	    sym.name != Names.init)
	    chk.earlyRefError(tree.pos, sym.kind == VAR ? sym : thisSym(env));

	return checkId(tree, env.enclClass.sym.type, sym, pkind, pt);
    }

    public Type _case(Select tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	int skind = 0;
	if (tree.name == Names._this || tree.name == Names._class) {
	    skind = TYP;
	} else {
	    if ((pkind & PCK) != 0) skind = skind | PCK;
	    if ((pkind & TYP) != 0) skind = skind | TYP | PCK;
	    if ((pkind & (VAL | MTH)) != 0) skind = skind | VAL | TYP;
	}
	Type site = attribTerm(tree.selected, env, skind, Type.noType);
	Symbol sitesym = TreeInfo.symbol(tree.selected);
	
	boolean selectSuperPrev = env.info.selectSuper;
	env.info.selectSuper =
	    sitesym != null &&
	    (sitesym.name == Names._super || sitesym.kind == TYP);

	Symbol sym = selectSym(tree, site, env, pt, pkind);
	tree.sym = sym;

	if (sym.kind == VAR) {
	    VarSymbol v = (VarSymbol)sym;
	    evalInit(v, env);
	    if (pkind == VAR)
		checkAssignable(tree.pos, v, tree.selected, env);
	}

	if (env.info.selectSuper) {
	    if ((sym.flags() & STATIC) == 0 &&
		sym.name != Names._this && sym.name != Names._super) {
		if (sitesym.name == Names._super) {
		    rs.checkNonAbstract(tree.pos, sym);
		} else if (sym.kind == VAR || sym.kind == MTH) {
		    rs.access(new Resolve.StaticError(sym),
			      tree.pos, site, sym.name);
		}
		if (env.info.isSelfCall &&
		    sym.name != Names.init &&
		    tree.name == Names._this &&
		    site.tsym == env.enclClass.sym) {
		    chk.earlyRefError(tree.pos, sym);
		}
		Type site1 = env.enclClass.sym.type.asSuper(site.tsym);
		if (site1 != null) site = site1;
	    }
	    env.info.selectSuper = selectSuperPrev;
	}
	return checkId(tree, site, sym, pkind, pt);
    }
//where
        /** determine symbol referenced by a Select expression,
	 *  @param pos    position for error reporting
	 *  @param site   the type of the selected expression
	 *  @param name   the selector name
	 *  @param env    the current environment
	 *  @param pt     the current prototype
	 *  @param pkind  the expected kind(s) of the Select expression
	 */
        private Symbol selectSym(Select tree, Type site,
				 Env<AttrContext> env, Type pt, int pkind) {
	    int pos = tree.pos;
	    Name name = tree.name;
	    switch (site.tag) {
	    case PACKAGE:
		return rs.access(
		    rs.findIdentInPackage(env, site.tsym, name, pkind),
		    pos, site, name);
	    case ARRAY:
	    case CLASS:
		if (pt.tag == METHOD) {
		    if (name == Names._super) {
			return rs.resolveSelfConstructor(
			    pos, env, name, pt.argtypes());
		    } else {
			return rs.resolveQualifiedMethod(
			    pos, env, site, name, Type.emptyList, pt.argtypes
());
		    }
		} else if (name == Names._this) {
		    return rs.resolveSelf(pos, env, site.tsym, name);
		} else if (name == Names._class) {
		    return new VarSymbol(
			STATIC | PUBLIC, Names._class, syms.classType, 
site.tsym);
		} else {
		    Symbol sym = rs.findIdentInType(env, site, name, pkind);
		    if (sym.kind >= rs.AMBIGUOUS) {
			if ((pkind & (TYP | PCK)) != 0) {
			    Name pname = TreeInfo.fullName(tree.selected);
			    if (pname != null) {
				PackageSymbol p = syms.reader.enterPackage
(pname);
				Symbol sym1 = rs.findIdentInPackage(
				    env, p, name, pkind);
				if (sym1.kind < sym.kind) sym = sym1;
			    }
			}
			sym = rs.access(sym, pos, site, name);
		    }
		    return sym;
		}
	    case TYPEVAR:
		return selectSym(tree, site.bound(), env, pt, pkind);
	    case ERROR:
		return Symbol.errSymbol;
	    default:
		if (name == Names._class) {
		    return new VarSymbol(
			STATIC | PUBLIC, Names._class, syms.classType, 
site.tsym);
		} else {	
		    log.error(pos, site + " cannot be dereferenced");
		}
		return Symbol.errSymbol;
	    }
	}

        /** determine type of identifier or select expression and check that
	 *  (1) the referenced symbol is not deprecated
	 *  (2) the symbol type is safe (@see checkSafe)
	 *  (3) if symbol is a variable, check that its type and kind are
	 *      compatible with the prototype and protokind.
	 *  (4) if symbol is a field of a raw type, which is being assigned to,
	 *      issue a warning if its type changes under erasure.
	 *  (5) if symbol is a method of a raw type, issue a warning if
	 *      its argument types change under erasure.
	 *  if checks succeed
	 *    if symbol is a constant return its constant type
	 *    else if symbol is a method return its result type
	 *    otherwise return its type
	 *  else return errType
	 */
        Type checkId(Tree tree, Type site, Symbol sym, int pkind, Type pt) {
	    if ((sym.flags() & DEPRECATED) != 0) warnDeprecated(tree.pos, sym);
	    Type owntype;
	    switch (sym.kind) {
	    case TYP:
		owntype = sym.type;
		if (owntype.tag == CLASS && owntype.typarams().nonEmpty()) {
		    owntype = new ClassType(
			owntype.outer(), Type.emptyList, owntype.tsym);
		}
		break;
	    case VAR:
		VarSymbol v = (VarSymbol)sym;
		if (!chk.unchecked &&
		    pkind == VAR &&
		    v.owner.kind == TYP &&
		    (v.flags() & STATIC) == 0 &&
		    site.tag == CLASS) {
		    Type s = site.asOuterSuper(v.owner);
		    if (s != null &&
			s.isRaw() &&
			!v.type.sameType(v.erasure())) {
			log.warning(
			    tree.pos,
			    "unchecked assignment to " + v + " of raw type " + 
site);
		    }
		}
		owntype = (sym.owner.kind == TYP)
		    ? site.memberType(sym)
		    : sym.type;
		if (v.constValue != null) owntype = owntype.constType
(v.constValue);
		break;
	    case MTH:
//todo: find out why this can be false
//		Base.assert(site.asOuterSuper(sym.owner) != null,
//			    sym + " " + site + " " + sym.owner);//DEBUG
		if (!chk.unchecked &&
		    (sym.flags() & STATIC) == 0 &&
		    site.tag == CLASS) {
		    Type s= site.asOuterSuper(sym.owner);
		    if (s != null &&
			s.isRaw() &&
			sym.name != Names.init &&
			!Type.sameTypes(
			    sym.type.argtypes(), sym.erasure().argtypes())) {
			log.warning(
			    tree.pos,
			    "unchecked call to " + sym + " of raw type " + 
site);
		    }
		}
		if (sym.name == Names.init) {
		    owntype = Type.voidType;
		} else {
		    owntype = rs.instantiate(
			site, sym, Type.emptyList, pt.argtypes());
		    if (owntype == null) {//debug
			log.error(
			    tree.pos, "internal error; cannot instantiate " +
			    sym + " at " + site + " to (" + pt.argtypes() 
+ ")");
		    }
		}
		break;
	    case PCK: case ERR:
		owntype = sym.type;
		break;
	    default:
		new Pretty().printExpr(tree);//debug
		throw new InternalError("unexpected kind: " + sym.kind);
	    }
	    infer.checkSafe(tree.pos, owntype, sym);
	    return check(tree, owntype, sym.kind, pkind, pt);
	}

        /** check that variable is initialized and evaluate the variable's
	 *  initializer, if not yet done
	 */
	private void checkInit(Tree tree, Env<AttrContext> env, VarSymbol v) {
//	    System.err.println(v + " " + ((v.flags() & STATIC) != 0) + " " +
//			       tree.pos + " " + v.pos + " " +
//			       (env.info.staticLevel > 
env.outer.info.staticLevel));//DEBUG
	    if (v.pos > tree.pos &&
		(v.owner.kind == MTH ||
		 (v.owner.kind == TYP &&
		  v.owner == env.info.scope.owner &&
		  ((v.flags() & STATIC) != 0) == Resolve.isStatic(env))) &&
		(env.tree.tag != Tree.ASSIGN || tree != ((Assign)env.tree).lhs))
		log.error(tree.pos, "illegal forward reference");
	    evalInit(v, env);
	}

	/** evaluate a final variable's initializer
	 *  and set variable's constValue
	 */
	void evalInit(VarSymbol v, Env<AttrContext> env) {
	    if (v.constValue instanceof Enter.EnvAttrContextBox) {
		Env<AttrContext> evalEnv =
		    ((Enter.EnvAttrContextBox)v.constValue).env;
		Name prev = log.useSource(evalEnv.toplevel.sourcefile);
		v.constValue = null;
		Type itype = attribExpr(
		    ((VarDef)evalEnv.tree).init, evalEnv, v.type);
		if (itype.constValue != null)
		    v.constValue = cfolder.coerce(itype, v.type).constValue;
		log.useSource(prev);
	    }
	}

        /** check that `sym' does not hide any symbols of the same name and
	 *  kind in `scope'
	 */
        boolean checkNotHiding(int pos, Symbol sym, Scope scope) {
	    Scope.Entry e = scope.lookup(sym.name);
	    while (e.scope != null) {
		if (e.sym.owner != sym.owner &&
		    e.sym.kind == sym.kind &&
		    e.sym.owner == scope.owner) {
		    log.error(
			pos, sym + " is inherited from " + sym.owner +
			" and hides a " + Resolve.kindName(sym.kind) +
			" of the same name" + e.sym.location() +
			". An explicit `this' qualifier must be used to select 
the desired instance  ");
		    return false;
		}
		e = e.next();
	    }
	    return true;
	}

    public Type _case(Literal tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	return check(
	    tree, litType(tree.typetag).constType(tree.value), VAL, pkind, pt);
    }
//where
        Type litType(int tag) {
	    return (tag == CLASS) ? syms.stringType : Type.typeOfTag[tag];
	}

    public Type _case(TypeIdent tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	return check(tree, Type.typeOfTag[tree.typetag], TYP, pkind, pt);
    }

    public Type _case(TypeArray tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type etype = attribType(tree.elemtype, env);
	return check(tree, new ArrayType(etype), TYP, pkind, pt);
    }

    /** attribute type application.
     *  bound checking is left until later, since types are attributed
     *  before supertype structure is completely known
     */
    public Type _case(TypeApply tree, Env<AttrContext> env) {
	Type pt = env.info.pt;
	int pkind = env.info.pkind;
	Type owntype = Type.errType;

	Type clazztype = chk.checkClassType(
	    tree.clazz.pos, attribType(tree.clazz, env));

	ListBuffer<Type> actbuf = new ListBuffer<Type>();
	for (List<Tree> l = tree.arguments; l.nonEmpty(); l = l.tail)
	    actbuf.append(chk.checkRefType(l.head.pos, attribType(l.head, 
env)));
	List<Type> actuals = actbuf.toList();

	if (clazztype.tag == CLASS) {
	    List<Type> formals = clazztype.tsym.type.typarams();
	    if (actuals.length() == formals.length()) {
		owntype = new ClassType(
		    clazztype.tsym.type.outer(), actuals, clazztype.tsym);
	    } else {
		log.error(
		    tree.pos,
		    (formals.length() != 0)
		        ? "wrong number of type arguments; required: " +
		          formals.length()
		        : "type " + clazztype + " does not take parameters");
		owntype = Type.errType;
	    }
	}
	return check(tree, owntype, TYP, pkind, pt);
    }

    public Type _case(TypeParameter tree, Env<AttrContext> env) {
	TypeVar a = (TypeVar)tree.type;
	if (tree.extBound != null)
	    a.bound = attribBase(tree.extBound, env, 0);
	else if (tree.implBound != null)
	    a.bound = attribBase(tree.implBound, env, INTERFACE);
	else
	    a.bound = syms.objectType;
	return a;
    }

    public Type _case(Erroneous tree, Env<AttrContext> env) {
	return tree.type = Type.errType;
    }

    public Type _case(Tree tree, Env<AttrContext> env) {
	throw new InternalError();
    }

    /** main method: attribute class definition associated given class symbol
     */
    public void attribClass(ClassSymbol c) {
	Type st = c.type.supertype();
	if (st.tag == CLASS) attribClass((ClassSymbol)st.tsym);
	if (c.owner.kind == TYP) attribClass((ClassSymbol)c.owner);
	
	if ((c.flags_field & UNFINISHED) != 0) {
	    Name prev = log.useSource(c.sourcefile);
	    c.flags_field &= ~UNFINISHED;

	    Env<AttrContext> env = enter.classEnvs.get(c);
	    enter.classEnvs.remove(c);

	    ClassDef tree = (ClassDef)env.tree;
	
	    implementInterfaceMethods(c, env);
	    chk.validateTypeParams(tree.typarams);
	    chk.validate(tree.extending);
	    chk.validate(tree.implementing);
	    if ((c.flags() & (ABSTRACT | INTERFACE)) == 0)
		chk.checkAllDefined(tree.pos, c);
	    chk.checkClassBounds(tree.pos, c);
	
	    if (tree.typarams.length() != 0 && c.subclass
(syms.throwableType.tsym))
		log.error(tree.pos,
			  "subtypes of java.lang.Throwable cannot have 
arguments");
	    tree.type = c.type;
	
	    for (List<TypeParameter> l = tree.typarams; l.nonEmpty(); l = 
l.tail)
		env.info.scope.enterIfAbsent(l.head.type.tsym);
	
	    if ((c.flags() & INTERFACE) == 0) {
		VarSymbol thisSym = new VarSymbol(FINAL, Names._this, c.type, 
c);
		thisSym.pos = Position.FIRSTPOS;
		env.info.scope.enter(thisSym);
		if (st.tag == CLASS) {
		    VarSymbol superSym = new VarSymbol(FINAL, Names._super, st, 
c);
		    superSym.pos = Position.FIRSTPOS;
		    env.info.scope.enter(superSym);
		}
		chk.checkImplementations(tree.pos, c);
	    } else {
		c.members_field = c.members_field.dup();
		implementInterfaceMethods(c, env);
		chk.checkImplementations(tree.pos, c);
		c.members_field = c.members_field.leave();
	    }
	
	    attribStats(tree.defs, env);
//	    checkConstructorsNonCyclic(tree.defs, env);
	    tree.type = c.type;

	    log.useSource(prev);
	}
    }
}
Comment 1 Olivier Thomann CLA 2002-03-27 17:42:30 EST
The selection parser seems to be in a infinite loop in the recovery mode. If it is not infinite, it is 
too long anyway.
Comment 2 Philipe Mulet CLA 2002-03-28 09:32:19 EST
Simpler test case:
[public class X {
    Object foo(Stack<X> s) {
    }
    List<T> bar(int pos, T x1, T x2, List<T> l) {
    }
}
]
Offending method is #bar, due to the combination of invalid return type and 
invalid last argument type. The recovery loops because it is branching back at 
the last closing parenthesis (not considering the one from #bar end of 
signature.

The forced argument reduction in case of recovery 
(RecoveredMethod#updateFromParserState) did not fix up the parser RParenPos, 
used then to update the next checkpoint. In this case, there is no right 
parenthesis consumed at this point yet.

Fixed.