Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8237072: [lworld] Add support for denoting and deriving the reference projection #32

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -326,7 +326,7 @@ protected String className(ClassType t, boolean longform, Locale locale) {
s = sym.name.toString();
}

return sym.isProjectedNullable() ? s + '?' : s;
return s;
}

/**
@@ -299,14 +299,6 @@ public Symbol clone(Symbol newOwner) {
throw new AssertionError();
}

public boolean isProjectedNullable() {
return false;
}

public ClassSymbol nullFreeTypeSymbol() {
return this.type.hasTag(CLASS) && ((this.flags() & VALUE) != 0) ? (ClassSymbol) this : null;
}

public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
return v.visitSymbol(this, p);
}
@@ -426,6 +418,29 @@ public boolean isValue() {
return (flags() & VALUE) != 0;
}

/**
* Is this a *derived* reference projection symbol ??
*/
public boolean isReferenceProjection() {
return false;
}

/**
* Return the value projection IFF 'this' happens to be derived reference projection, null
* otherwise.
*/
public Symbol valueProjection() {
return null;
}

/**
* Return the reference projection IFF 'this' happens to be value projection, null
* otherwise.
*/
public Symbol referenceProjection() {
return null;
This conversation was marked as resolved by sadayapalam

This comment has been minimized.

@mcimadamore

mcimadamore Apr 30, 2020
Collaborator

How much would it help to have this return this ? It seems to me that there a lot of if <value> ... referenceProjection() going around.

This comment has been minimized.

@sadayapalam

sadayapalam May 1, 2020
Author Collaborator

It could result in cleaner code. I have this one JDK-8244232 to cover it.

}

public boolean isPublic() {
return (flags_field & Flags.AccessFlags) == PUBLIC;
}
@@ -528,6 +543,8 @@ public ClassSymbol enclClass() {
}

/** The outermost class which indirectly owns this symbol.
* 'outermost' being a lexical construct, should transcend
* projections
*/
public ClassSymbol outermostClass() {
Symbol sym = this;
@@ -536,7 +553,7 @@ public ClassSymbol outermostClass() {
prev = sym;
sym = sym.owner;
}
return (ClassSymbol) prev;
return (ClassSymbol) (prev!= null && prev.isReferenceProjection() ? prev.valueProjection() : prev);
}

/** The package which indirectly owns this symbol.
@@ -1299,6 +1316,12 @@ public RootPackageSymbol(Name name, Symbol owner, MissingInfoHandler missingInfo
*/
private List<RecordComponent> recordComponents = List.nil();

/* the 'other' projection: If 'this' is an inline class then 'projection' is its reference projection
and vice versa.
*/
public ClassSymbol projection;


public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
super(TYP, flags, name, type, owner);
this.members_field = null;
@@ -1359,8 +1382,7 @@ public String className() {
return
Log.getLocalizedString("anonymous.class", flatname);

String s = fullname.toString();
return isProjectedNullable() ? s + '?' : s;
return fullname.toString();
}

@DefinedBy(Api.LANGUAGE_MODEL)
@@ -1613,6 +1635,61 @@ public void setAnnotationTypeMetadata(AnnotationTypeMetadata a) {
public boolean isRecord() {
return (flags_field & RECORD) != 0;
}

@Override
public boolean isReferenceProjection() {
return projection != null && projection.isValue();
}

@Override
public ClassSymbol valueProjection() {
return isReferenceProjection() ? projection : null;
}

@Override
public ClassSymbol referenceProjection() {
if (!isValue() || projection != null)
return projection;

ClassType ct = (ClassType) this.type;
ClassType projectedType = new ClassType(ct.getEnclosingType(), ct.typarams_field, null);
projectedType.allparams_field = ct.allparams_field;
projectedType.supertype_field = ct.supertype_field;

projectedType.interfaces_field = ct.interfaces_field;
projectedType.all_interfaces_field = ct.all_interfaces_field;
projectedType.projection = ct;
ct.projection = projectedType;

Name projectionName = this.name.append('$', this.name.table.names.ref);
long projectionFlags = (this.flags() & ~(VALUE | UNATTRIBUTED));

projection = new ClassSymbol(projectionFlags, projectionName, projectedType, this.owner);
projection.members_field = WriteableScope.create(projection);
for (Symbol s : this.members().getSymbols(s->(s.kind == MTH || s.kind == VAR), NON_RECURSIVE)) {
Symbol clone = null;
if (s.kind == MTH) {
MethodSymbol valMethod = (MethodSymbol)s;
MethodSymbol refMethod = valMethod.clone(projection);
valMethod.projection = refMethod;
refMethod.projection = valMethod;
clone = refMethod;
} else if (s.kind == VAR) {
VarSymbol valVar = (VarSymbol)s;
VarSymbol refVar = valVar.clone(projection);
valVar.projection = refVar;
refVar.projection = valVar;
clone = refVar;
}
projection.members_field.enter(clone);
}
projection.completer = Completer.NULL_COMPLETER;
projection.sourcefile = this.sourcefile;
projection.flatname = this.flatname.append('$', this.name.table.names.ref);
projection.projection = this;
projectedType.tsym = projection;
return projection;
}
}


@@ -1635,6 +1712,11 @@ public boolean isRecord() {
*/
public int adr = -1;

/* The 'other' projection: If 'this' is a field of an inline class, then 'projection' is the
its doppleganger in its referene projection class and vice versa.
*/
public VarSymbol projection;

/** Construct a variable symbol, given its flags, name, type and owner.
*/
public VarSymbol(long flags, Name name, Type type, Symbol owner) {
@@ -1667,6 +1749,7 @@ public Object poolKey(Types types) {
v.pos = pos;
v.adr = adr;
v.data = data;
v.projection = projection;
// System.out.println("clone " + v + " in " + newOwner);//DEBUG
return v;
}
@@ -1719,6 +1802,18 @@ public void setLazyConstValue(final Env<AttrContext> env,
setData((Callable<Object>)() -> attr.attribLazyConstantValue(env, variable, type));
}

@Override
public VarSymbol referenceProjection() {
return this.owner.isValue() ?
this.owner.referenceProjection() != null ? projection : null
: null;
}

@Override
public VarSymbol valueProjection() {
return projection != null ? projection.owner.isValue() ? projection : null: null;
}

/**
* The variable's constant value, if this is a constant.
* Before the constant value is evaluated, it points to an
@@ -1869,6 +1964,11 @@ public boolean isPreserved() {
*/
public Attribute defaultValue = null;

/* The 'other' projection: If 'this' is a method of an inline class, then 'projection' is the
its doppleganger in its referene projection class and vice versa.
*/
public MethodSymbol projection;

/** Construct a method symbol, given its flags, name, type and owner.
*/
public MethodSymbol(long flags, Name name, Type type, Symbol owner) {
@@ -1891,6 +1991,7 @@ public Object poolKey(Types types) {
}
};
m.code = code;
m.projection = projection;
return m;
}

@@ -2039,6 +2140,16 @@ public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean
boolean requireConcreteIfInherited) {
if (isConstructor() || _other.kind != MTH) return false;


/* If any inline types are involved, ask the same question in the reference universe,
where the hierarchy is navigable
*/
if (origin.isValue())
origin = (TypeSymbol) origin.referenceProjection();

if (this.owner.isValue())
return this.projection.overrides(_other, origin, types, checkResult, requireConcreteIfInherited);

if (this == _other) return true;
MethodSymbol other = (MethodSymbol)_other;

@@ -2093,6 +2204,15 @@ private boolean isOverridableIn(TypeSymbol origin) {

@Override
public boolean isInheritedIn(Symbol clazz, Types types) {

/* If any inline types are involved, ask the same question in the reference universe,
where the hierarchy is navigable
*/
if (clazz.isValue())
clazz = clazz.referenceProjection();
if (this.owner.isValue())
return this.projection.isInheritedIn(clazz, types);

switch ((int)(flags_field & Flags.AccessFlags)) {
case PUBLIC:
return !this.owner.isInterface() ||
@@ -2107,6 +2227,18 @@ public boolean isLambdaMethod() {
return (flags() & LAMBDA_METHOD) == LAMBDA_METHOD;
}

@Override
public MethodSymbol referenceProjection() {
return this.owner.isValue() ?
this.owner.referenceProjection() != null ? projection : null
: null;
}

@Override
public MethodSymbol valueProjection() {
return projection != null ? projection.owner.isValue() ? projection : null : null;
}

/** override this method to point to the original enclosing method if this method symbol represents a synthetic
* lambda method
*/
@@ -235,6 +235,22 @@ public Type(TypeSymbol tsym, TypeMetadata metadata) {
this.metadata = metadata;
}

public boolean isValue() {
return false;
}

public boolean isReferenceProjection() {
return false;
}

public Type valueProjection() {
return null;
}

public Type referenceProjection() {
return null;
}

/**
* A subclass of {@link Types.TypeMapping} which applies a mapping recursively to the subterms
* of a given type expression. This mapping returns the original type is no changes occurred
@@ -1008,6 +1024,11 @@ public String toString() {
*/
public List<Type> all_interfaces_field;

/* The 'other' projection: If 'this' is type of an inline class, then 'projection' is the
its doppleganger in its referene projection world and vice versa.
*/
public ClassType projection;

public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) {
this(outer, typarams, tsym, TypeMetadata.EMPTY);
}
@@ -1111,7 +1132,7 @@ private String className(Symbol sym, boolean longform) {
} else {
s = sym.name.toString();
}
return sym.isProjectedNullable() ? s + '?' : s;
return s;
}

@DefinedBy(Api.LANGUAGE_MODEL)
@@ -1161,6 +1182,54 @@ public boolean isReference() {
return true;
}

@Override
public boolean isValue() {
return tsym != null && tsym.isValue();
}

@Override
public boolean isReferenceProjection() {
return tsym != null && tsym.isReferenceProjection();
}

@Override
public Type valueProjection() {
if (!isReferenceProjection() || projection != null)
This conversation was marked as resolved by sadayapalam

This comment has been minimized.

@mcimadamore

mcimadamore Apr 30, 2020
Collaborator

Question here - since you have two symbols, getting a reference projection and value projection shouldn't be as simple as doing tsym.XYZprojection().type ? Why do we need to create new types here?

This comment has been minimized.

@sadayapalam

sadayapalam May 1, 2020
Author Collaborator

FTR, this is to preserve any parameterizations. The value projection of V.ref is V.val and not V.val

return projection;

// Make a best case effort to cache the other projection.
ClassSymbol valueClass = (ClassSymbol) tsym.valueProjection();

projection = new ClassType(outer_field, typarams_field, valueClass);
projection.allparams_field = allparams_field;
projection.supertype_field = supertype_field;

projection.interfaces_field = interfaces_field;
projection.all_interfaces_field = all_interfaces_field;
projection.projection = this;
return projection;
}

// return the reference projection type preserving parameterizations
@Override
public ClassType referenceProjection() {

if (!isValue() || projection != null)
return projection;

// make a best case effort to cache the other projection.
ClassSymbol refClass = (ClassSymbol) tsym.referenceProjection();

projection = new ClassType(outer_field, typarams_field, refClass);
projection.allparams_field = allparams_field;
projection.supertype_field = supertype_field;

projection.interfaces_field = interfaces_field;
projection.all_interfaces_field = all_interfaces_field;
projection.projection = this;
return projection;
}

@Override
public boolean isNullOrReference() {
return true;