When working on our GPCE Mint tutorial, Eddy and I realized that there is a problem when programmers use type variables inside brackets. A method like
[cc lang=”java”]public separable
return <| ( `(lfTest.eval(e,f).booleanCodeValue()) ?
`c2 : `c1 ) |>;
}[/cc]
causes Mint to generate code containing the free type variable [cci lang=”java”]X[/cci]. There is no way to get any type information from a type variable at runtime, e.g. by doing [cci lang=”java”]X.class[/cci], so instead we decided to require the user to have a final instance of [cci lang=”java”]Class
This was a pragmatic solution that seems to work pretty well. The method above can be rewritten as
[cc lang=”java”]public separable
final Class
return <| ( `(lfTest.eval(e,f).booleanCodeValue()) ?
`c2 : `c1 ) |>;
}[/cc]
To implement this, we had to find all variables of type [cci lang=”java”]Class
[cc lang=”java”] /** This method returns a list of all VarSymbols of type Class
List
// System.out.println(“env = “+env);
List
Scope current = env.info.scope;
// System.out.println(“Scope: “+current);
while(current != null) { // also go into the outer (enclosing) scopes
// for(Symbol s: current.elems) {
for (Scope.Entry e = current.elems; e != null; e = e.sibling) {
ret = processPotentialClassVarInScope(e.sym, ret);
}
current = current.next;
}
// System.out.println(“Asking for vars in “+env.enclClass.sym);
ret = _getClassVarsInScope(env, ret);
return ret.reverse();
}
List
// System.out.println(“in scope: “+s+” : “+s.getClass().getSimpleName());
if (s instanceof VarSymbol) {
VarSymbol vs = (VarSymbol)s;
if ((vs.type.tsym == syms.classType.tsym) &&
((vs.flags() & FINAL) != 0) &&
(vs.type.getTypeArguments().nonEmpty()) &&
(vs.type.getTypeArguments().head instanceof TypeVar)) {
// vs is of type Class
ret = ret.prepend(vs);
}
}
return ret;
}
List
Env
boolean staticOnly = false;
while (env1.outer != null) {
if (rs.isStatic(env1)) staticOnly = true;
Scope.Entry e = env1.info.scope.elems;
while (e != null) {
Symbol sym = e.sym;
if (!(staticOnly &&
sym.kind == VAR &&
sym.owner.kind == TYP &&
(sym.flags() & STATIC) == 0)) {
ret = processPotentialClassVarInScope(sym, ret);
}
ret = _getClassFieldsInScope(env1, env1.enclClass.sym.type, env1.enclClass.sym, ret);
e = e.sibling;
}
ret = _getClassFieldsInScope(env1, env1.enclClass.sym.type, env1.enclClass.sym, ret);
if ((env1.enclClass.sym.flags() & STATIC) != 0) staticOnly = true;
env1 = env1.outer;
}
ret = _getClassFieldsInScope(env, syms.predefClass.type, syms.predefClass, ret);
return ret;
}
List
Type site,
TypeSymbol c,
List
while (c.type.tag == TYPEVAR)
c = c.type.getUpperBound().tsym;
Scope.Entry e = c.members().elems;
while (e != null) {
if (e.sym.kind == VAR && (e.sym.flags_field & SYNTHETIC) == 0) {
if (rs.isAccessible(env, site, e.sym)) {
ret = processPotentialClassVarInScope(e.sym, ret);
}
}
e = e.sibling;
}
Type st = types.supertype(c.type);
if (st != null && (st.tag == CLASS || st.tag == TYPEVAR)) {
ret = _getClassFieldsInScope(env, site, st.tsym, ret);
}
for (Type it: types.interfaces(c.type)) {
ret = _getClassFieldsInScope(env, site, it.tsym, ret);
}
return ret;
}[/cc]
A new Mint release can be expected shortly.