/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2010. */ package x10.ast; import java.util.Collections; import java.util.List; import polyglot.ast.Ambiguous; import polyglot.ast.Call; import polyglot.ast.Disamb_c; import polyglot.ast.Expr; import polyglot.ast.Field; import polyglot.ast.Id; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.PackageNode; import polyglot.ast.Receiver; import polyglot.ast.Special; import polyglot.ast.TypeNode; import polyglot.types.ClassType; import polyglot.types.Context; import polyglot.types.FieldDef; import polyglot.types.FieldInstance; import polyglot.types.LocalInstance; import polyglot.types.MemberInstance; import polyglot.types.NoClassException; import polyglot.types.Package; import polyglot.types.QName; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.Types; import polyglot.types.VarInstance; import polyglot.types.CodeDef; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.visit.ContextVisitor; import x10.errors.Errors; import x10.extension.X10Del; import x10.types.ClosureDef; import x10.types.X10ClassType; import polyglot.types.Context; import x10.types.X10FieldInstance; import x10.types.MethodInstance; import x10.types.matcher.X10FieldMatcher; import polyglot.types.TypeSystem; import polyglot.types.TypeSystem_c; import x10.types.checker.Checker; public class X10Disamb_c extends Disamb_c { public String toString() { return "X10Disamb(" + amb.getClass().getName() + ": " + amb + ")"; } @Override protected Node disambiguateNoPrefix() throws SemanticException { if (name.id()== TypeSystem_c.voidName) return makeTypeNode(ts.Void()); Context c = (Context) this.c; TypeSystem ts = (TypeSystem) this.ts; if (c.inDepType()) { Type t = c.currentDepType(); if (exprOK()) { // First try local variables. VarInstance<?> vi = c.pop().findVariableSilent(name.id()); if (vi != null && vi.def() == c.varWhoseTypeIsBeingElaborated()) { Expr e = ((NodeFactory) nf).Self(pos); e = e.type(t); return e; } if (vi instanceof LocalInstance) { Node n = disambiguateVarInstance(vi); if (n != null) return n; } // Now try properties. FieldInstance fi = null; try { fi = ts.findField(t, t, this.name.id(), c); } catch (SemanticException ex) { } if (fi != null && vi instanceof FieldInstance && !c.inStaticContext() && !fi.flags().isStatic() && !vi.flags().isStatic()) { Receiver e = makeMissingFieldTarget((FieldInstance) vi); throw new SemanticException("Ambiguous reference to field " + this.name + "; both self." + name + " and " + e + "." + name + " match.", pos); } if (fi == null && vi instanceof FieldInstance && !vi.flags().isStatic() && c.inStaticContext()) { throw new Errors.CannotAccessNonStaticFromStaticContext((FieldInstance) vi, pos); } if (fi instanceof X10FieldInstance) { X10FieldInstance xfi = (X10FieldInstance) fi; if (xfi.isProperty()) { Field f = nf.Field(pos, makeMissingPropertyTarget(xfi, t), this.name); f = f.fieldInstance(xfi); Type ftype = Checker.rightType(xfi.rightType(), xfi.x10Def(), f.target(), c); f = (Field) f.type(ftype); return f; } else { if (vi == null) { throw new SemanticException("Field \"" + name + "\" is not a property of " + t + ". Only properties may appear unqualified or prefixed with self in a dependent clause."); } else { // found it as a field of an enclosing class, not of self. // fall thru to lookup } } } if (vi != null) { Node n = disambiguateVarInstance(vi); if (n != null) return n; } // Now try 0-ary property methods. try { MethodInstance mi = ts.findMethod(t, ts.MethodMatcher(t, this.name.id(), Collections.<Type>emptyList(), c)); if (mi.flags().isProperty()) { Call call = nf.Call(pos, makeMissingPropertyTarget(mi, t), this.name); call = call.methodInstance(mi); Type ftype = Checker.rightType(mi.rightType(), mi.x10Def(), call.target(), c); call = (Call) call.type(ftype); return call; } } catch (SemanticException e) { } } if (typeOK()) { try { Type ct = ts.findMemberType(t, this.name.id(), c); return makeTypeNode(ct); } catch (SemanticException e) { } } } if (exprOK()) { // First try local variables and fields. VarInstance<?> vi = c.findVariableSilent(name.id()); if (vi instanceof FieldInstance) { FieldInstance fi = (FieldInstance) vi; TypeSystem xts = (TypeSystem) v.typeSystem(); Context p = c; // FIXME: [IP] should we pop back to the right context before proceeding? //while (p.pop() != null && ((p.currentClass() != null && !xts.typeEquals(p.currentClass(), fi.container(), p)) || p.currentCode() instanceof ClosureDef)) // p = p.pop(); if (p.inStaticContext() && !fi.flags().isStatic()) throw new Errors.CannotAccessNonStaticFromStaticContext(fi, pos); } if (vi != null) { Node n = disambiguateVarInstance(vi); if (n != null) return n; } // Now try 0-ary property methods. try { MethodInstance mi = c.findMethod(ts.MethodMatcher(null, name.id(), Collections.<Type>emptyList(), c)); if (mi.flags().isProperty()) { Call call = nf.Call(pos, makeMissingMethodTarget(mi), this.name); call = call.methodInstance(mi); Type ftype = Checker.rightType(mi.rightType(), mi.x10Def(), call.target(), c); call = (Call) call.type(ftype); return call; } } catch (SemanticException e) { int q=1; } } // no variable found. try types. if (typeOK()) { try { List<Type> n = c.find(ts.TypeMatcher(name.id())); if (n.size() > 1) { throw new SemanticException("Ambiguous type "+name.id()+"\nPossible matches: "+n, pos); } for (Type type : n) { return makeTypeNode(type); } } catch (NoClassException e1) { if (!name.id().toString().equals(e1.getClassName())) { // hmm, something else must have gone wrong // rethrow the exception throw e1; } // couldn't find a type named name. // It must be a package--ignore the exception. } } // Must be a package then... if (packageOK()) { try { Package p = ts.packageForName(QName.make(null, name.id())); return nf.PackageNode(pos, Types.ref(p)); } catch (SemanticException e) { } Package p = ts.createPackage(QName.make(null, name.id())); return nf.PackageNode(pos, Types.ref(p)); } return null; } @Override protected Node disambiguateTypeNodePrefix(TypeNode tn) throws SemanticException { // TODO: typedef members return super.disambiguateTypeNodePrefix(tn); } @Override protected Node disambiguatePackagePrefix(PackageNode pn) throws SemanticException { // TODO: typedef members return super.disambiguatePackagePrefix(pn); } @Override protected Node disambiguateExprPrefix(Expr e) throws SemanticException { // TODO: typedef members Type t = e.type(); Context xc = (Context) this.c; // If in a class header, don't search the supertypes of this class. if (xc.inSuperTypeDeclaration()) { Type tType = t; Type tBase = Types.baseType(tType); if (tBase instanceof X10ClassType) { X10ClassType tCt = (X10ClassType) tBase; if (tCt.def() == xc.supertypeDeclarationType()) { if (exprOK()) { // The only fields in scope here are the ones explicitly declared here. for (FieldDef fd : tCt.x10Def().properties()) { if (fd.name().equals(name.id())) { FieldInstance fi = fd.asInstance(); fi = X10FieldMatcher.instantiateAccess((X10FieldInstance)fi,name.id(),tType,false,c); if (fi != null) { // Found! X10Field_c result = (X10Field_c) nf.Field(pos, e, name); result = (X10Field_c) result.fieldInstance(fi).type(fi.type()); return result; } } } return null; } } } } if (exprOK()) { try { return super.disambiguateExprPrefix(e); } catch (SemanticException ex) { } // Now try 0-ary property methods. try { MethodInstance mi = (MethodInstance) ts.findMethod(e.type(), ts.MethodMatcher(e.type(), name.id(), Collections.<Type>emptyList(), c)); if (mi.flags().isProperty()) { Call call = nf.Call(pos, e, this.name); call = call.methodInstance(mi); Type ftype = Checker.rightType(mi.rightType(), mi.x10Def(), call.target(), c); call = (Call) call.type(ftype); return call; } } catch (SemanticException ex) { } } return null; } @Override public Node disambiguate(Ambiguous amb, ContextVisitor v, Position pos, Node prefix, Id name) throws SemanticException { Node n = super.disambiguate(amb, v, pos, prefix, name); if (n != null) { n = ((X10Del) n.del()).annotations(((X10Del) amb.del()).annotations()); n = ((X10Del) n.del()).setComment(((X10Del) amb.del()).comment()); } return n; } protected Receiver makeMissingFieldTarget(FieldInstance fi) { return makeMissingFieldTarget(fi, pos, v); } public static Receiver makeMissingFieldTarget(FieldInstance fi, Position pos, ContextVisitor v) { Receiver r = null; NodeFactory nf = v.nodeFactory(); TypeSystem ts = v.typeSystem(); Context c = v.context(); ClassType cur = c.currentClass(); try { Position prefixPos = pos.startOf().markCompilerGenerated(); if (fi.flags().isStatic()) { r = nf.CanonicalTypeNode(prefixPos, fi.container()); } else { // The field is non-static, so we must prepend with // "this", but we need to determine if the "this" // should be qualified. Get the enclosing class which // brought the field into scope. This is different // from fi.container(). fi.container() returns a super // type of the class we want. ClassType scope = c.findFieldScope(fi.name()); if (cur!=null && cur.flags()!=null && cur.flags().isStatic()) { // The class is an inner static class scope = cur; } else if (c.inSuperTypeDeclaration()) { cur = c.supertypeDeclarationType().asType(); scope = cur; } assert scope != null; if (! ts.typeEquals(scope, cur, c)) { r = (Special) nf.This(prefixPos, nf.CanonicalTypeNode(prefixPos, scope)); } else { r = (Special) nf.This(prefixPos); } r = (Special) r.del().typeCheck(v); } } catch (SemanticException cause) { Position p = r == null ? pos : r.position(); throw new InternalCompilerError("Unexpected exception when typechecking "+r, p, cause); } return r; } protected Receiver makeMissingMethodTarget(MethodInstance mi) throws SemanticException { Receiver r; Context c = (Context) this.c; ClassType cur =c.currentClass(); if (c.inSuperTypeDeclaration()) cur = c.supertypeDeclarationType().asType(); if (mi.flags().isStatic()) { r = nf.CanonicalTypeNode(pos.startOf(), mi.container()); } else { // The field is non-static, so we must prepend with // "this", but we need to determine if the "this" // should be qualified. Get the enclosing class which // brought the field into scope. This is different // from fi.container(). fi.container() returns a super // type of the class we want. ClassType scope = c.findMethodScope(name.id()); assert scope != null; if (! ts.typeEquals(scope, cur, c)) { r = (Special) nf.This(pos.startOf(), nf.CanonicalTypeNode(pos.startOf(), scope)).del().typeCheck(v); } else { r = (Special) nf.This(pos.startOf()).del().typeCheck(v); } } return r; } protected Receiver makeMissingPropertyTarget(MemberInstance<?> fi, Type currentDepType) throws SemanticException { Receiver r; if (fi.flags().isStatic()) { r = nf.CanonicalTypeNode(pos.startOf(), fi.container()); } else { // The field is non-static, so we must prepend with self. Expr e = ((NodeFactory) nf).Self(pos); e = e.type(currentDepType); r = e; } return r; } }