/*
* 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 polyglot.ast.Node;
import polyglot.ast.Special_c;
import polyglot.ast.TypeNode;
import polyglot.types.ClassType;
import polyglot.types.CodeDef;
import polyglot.types.LazyRef_c;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.Types;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import polyglot.visit.ContextVisitor;
import x10.constraint.XFailure;
import x10.constraint.XVar;
import x10.constraint.XTerm;
import x10.errors.Errors;
import x10.errors.Errors.IllegalConstraint;
import x10.types.ConstrainedType;
import x10.types.X10ConstructorDef;
import polyglot.types.Context;
import x10.types.ThisDef;
import x10.types.X10MemberDef;
import x10.types.X10MethodDef;
import x10.types.X10ParsedClassType;
import x10.types.X10ProcedureDef;
import polyglot.types.TypeSystem;
import x10.types.XTypeTranslator;
import x10.types.checker.PlaceChecker;
import x10.types.constraints.CConstraint;
import x10.types.constraints.CConstraint;
import x10.types.constraints.CThis;
import x10.types.constraints.ConstraintManager;
import x10.types.constraints.XConstrainedTerm;
public class X10Special_c extends Special_c implements X10Special {
public X10Special_c(Position pos, Kind kind, TypeNode qualifier) {
super(pos, kind, qualifier);
}
public static X10Special self(Position pos) {
X10Special_c self = new X10Special_c(pos, SELF, null);
return self;
}
public boolean isSelf() { return kind == SELF; }
/** Type check the expression. */
public Node typeCheck(ContextVisitor tc) {
TypeSystem ts = (TypeSystem) tc.typeSystem();
Context c = (Context) tc.context();
if (isSelf()) {
Type tt = c.currentDepType();
if (tt == null) {
Errors.issue(tc.job(),
new Errors.SelfMayOnlyBeUsedWithinDependentType(position()));
tt = ts.unknownType(position());
}
// The type of self should not include a dep clause; otherwise
// self in C{c} could have type C{c}, causing an infinite regress
// later in type checking.
tt = Types.baseType(tt);
assert tt != null;
return type(tt);
}
Type t = null;
CodeDef code = c.currentCode();
if (code instanceof X10MemberDef) {
ThisDef thisDef = ((X10MemberDef) code).thisDef();
if (null == thisDef) {
throw new InternalCompilerError(position(), "X10Special_c.typeCheck: thisDef is null for containing code " +code);
}
assert (thisDef != null);
c.recordCapturedVariable(thisDef.asInstance());
}
if (qualifier == null) {
// an unqualified "this"
t = c.currentClass();
// If in the class header declaration, make this refer to the current class, not the enclosing class (or null).
if (c.inSuperTypeDeclaration()) {
if (kind == SUPER) {
Errors.issue(tc.job(),
new Errors.CannotReferToSuperFromDeclarationHeader(position()),
this);
}
t = c.supertypeDeclarationType().asType();
}
// Use the constructor return type, not the base type.
if (c.currentDepType() == null)
if (code instanceof X10ConstructorDef) {
X10ConstructorDef cd = (X10ConstructorDef) code;
Type returnType = (Type) cd.returnType().get();
returnType = ts.expandMacros(returnType);
t = returnType;
}
}
else {
if (qualifier.type().isClass()) {
ClassType ct = qualifier.type().toClass();
t=ct;
if (!c.currentClass().hasEnclosingInstance(ct)) {
Errors.issue(tc.job(),
new Errors.NestedClassMissingEclosingInstance(c.currentClass(), ct, qualifier.position()),
this);
}
}
else {
Errors.issue(tc.job(),
new Errors.InvalidQualifierForSuper(qualifier.position()),
this);
}
}
if (t == null || (c.inStaticContext() && ts.typeEquals(t, c.currentClass(), c))) {
// trying to access "this" or "super" from a static context.
Errors.issue(tc.job(),
new Errors.CannotAccessNonStaticFromStaticContext(position()));
}
X10Special result = this;
TypeSystem xts = (TypeSystem) ts;
assert (t.isClass());
// Instantiate with the class's type arguments
t = Types.instantiateTypeParametersExplicitly(t);
if (kind == THIS) {
Type tt = Types.baseType(t);
CConstraint cc = Types.xclause(t);
cc = cc == null ? ConstraintManager.getConstraintSystem().makeCConstraint() : cc.copy();
try {
// In case there is a qualifier, bind self to
// both the thisVar of the corresponding outer context
// and to qualifier.this, where this is the current this
// variable
XTypeTranslator xt = xts.xtypeTranslator();
XVar var = (XVar) xt.translate(cc, this, c);
/* XVar qualifiedVar = (XVar) xt.translateSpecialAsQualified(cc, this, c);
if (qualifiedVar != null && qualifiedVar != var
&& qualifiedVar instanceof QualifiedVar) {
QualifiedVar qVar = (QualifiedVar) qualifiedVar;
if (qVar.receiver() != var) {
cc.addSelfBinding(qVar);
}
}*/
if (var != null) {
cc.addSelfBinding(var);
}
//PlaceChecker.AddThisHomeEqualsPlaceTerm(cc, var, c);
} catch (IllegalConstraint z) {
Errors.issue(tc.job(), z);
}
tt = Types.xclause(Types.baseType(tt), cc);
result = (X10Special) type(tt);
}
else if (kind == SUPER) {
Type superClass = Types.superClass(t);
if (superClass == null) {
Errors.issue(tc.job(), new SemanticException("One cannot use super in a class that does not extend anything.", position()));
// [DC] this seems like a reasonable substitute...
result = (X10Special) type(ts.Null());
} else {
Type tt = Types.baseType(superClass);
CConstraint cc = Types.xclause(superClass);
cc = cc == null ? ConstraintManager.getConstraintSystem().makeCConstraint() : cc.copy();
try {
XVar var = (XVar) xts.xtypeTranslator().translate(cc, this, c);
if (var != null) {
cc.addSelfBinding(var);
//PlaceChecker.AddThisHomeEqualsPlaceTerm(cc, var, c);
}
} catch (IllegalConstraint z) {
Errors.issue(tc.job(), z);
}
tt = Types.xclause(Types.baseType(tt), cc);
result = (X10Special) type(tt);
}
}
assert result.type() != null;
if (code instanceof X10ProcedureDef) {
X10ProcedureDef pi = (X10ProcedureDef) code;
CConstraint guard = Types.get(pi.guard());
if (guard != null && ! guard.valid()) {
Type newType = result.type();
CConstraint dep = Types.xclause(newType);
if (dep == null)
dep = guard.copy();
else
dep.addIn(guard);
if (! dep.consistent()) {
Errors.issue(tc.job(), new Errors.InconsistentType(newType, position()));
}
newType = Types.xclause(Types.baseType(newType), dep);
return result.type(newType);
}
}
return result;
}
public String toString() {
String typeString = "";
Type type = type();
if (type != null && type.isClass()) {
typeString = "(:" + type.toClass().toString() + ")";
}
return (qualifier == null ? "" : qualifier.toString() + ".") + kind + typeString;
}
}