Skip to content

Commit e2c3790

Browse files
committed
Further generics fixes
1 parent f9a90b7 commit e2c3790

24 files changed

Lines changed: 218 additions & 170 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ nbactions.xml
1717
/preferences.*
1818
.DS_Store
1919
/test-backend/
20+
.mvn/
2021
/nbproject/
2122
dependency-reduced-pom.xml
2223

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@
10711071
<plugin>
10721072
<groupId>org.jacoco</groupId>
10731073
<artifactId>jacoco-maven-plugin</artifactId>
1074-
<version>0.8.7</version>
1074+
<version>0.8.14</version>
10751075
<executions>
10761076
<execution>
10771077
<id>default-prepare-agent</id>
@@ -1177,7 +1177,7 @@
11771177
<plugin>
11781178
<groupId>org.jacoco</groupId>
11791179
<artifactId>jacoco-maven-plugin</artifactId>
1180-
<version>0.8.7</version>
1180+
<version>0.8.14</version>
11811181
<configuration>
11821182
<skip>true</skip>
11831183
</configuration>
@@ -1242,7 +1242,7 @@
12421242
<plugin>
12431243
<groupId>org.jacoco</groupId>
12441244
<artifactId>jacoco-maven-plugin</artifactId>
1245-
<version>0.8.7</version>
1245+
<version>0.8.14</version>
12461246
<reportSets>
12471247
<reportSet>
12481248
<reports>

src/main/java/com/laytonsmith/core/MethodScriptCompiler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.laytonsmith.core.compiler.TokenStream;
2222
import com.laytonsmith.core.compiler.analysis.StaticAnalysis;
2323
import com.laytonsmith.core.constructs.CBareString;
24+
import com.laytonsmith.core.constructs.CClassType;
2425
import com.laytonsmith.core.constructs.CDecimal;
2526
import com.laytonsmith.core.constructs.CDouble;
2627
import com.laytonsmith.core.constructs.CFunction;
@@ -36,7 +37,7 @@
3637
import com.laytonsmith.core.constructs.CVoid;
3738
import com.laytonsmith.core.constructs.Construct;
3839
import com.laytonsmith.core.constructs.IVariable;
39-
import com.laytonsmith.core.constructs.SourceType;
40+
import com.laytonsmith.core.constructs.LeftHandSideType;
4041
import com.laytonsmith.core.constructs.Target;
4142
import com.laytonsmith.core.constructs.Token;
4243
import com.laytonsmith.core.constructs.Token.TType;
@@ -1754,7 +1755,7 @@ public static ParseTree compile(TokenStream stream, Environment env,
17541755
if(!(previous.getData() instanceof SourceType st)) {
17551756
throw new ConfigCompileException("Unexpected varargs token (\"...\"). This can only be used with types.", t.target);
17561757
}
1757-
previous.setData(st.asVariadicType(env));
1758+
previous.setData(st.asLeftHandSideType().asVariadicType(t.getTarget(), env));
17581759
continue;
17591760
} else if(t.type == TType.LIT) {
17601761
Construct c;

src/main/java/com/laytonsmith/core/Procedure.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ public class Procedure implements Cloneable {
5252
private Map<String, IVariable> varList;
5353
private final Map<String, Mixed> originals = new HashMap<>();
5454
private final List<IVariable> varIndex = new ArrayList<>();
55-
private final List<Boolean> isVarArg;
5655
private ParseTree tree;
57-
private CClassType returnType;
56+
private LeftHandSideType returnType;
5857
private boolean possiblyConstant = false;
5958
private SmartComment procComment;
6059

@@ -64,7 +63,7 @@ public class Procedure implements Cloneable {
6463
*/
6564
private final Target definedAt;
6665

67-
public Procedure(String name, CClassType returnType, List<IVariable> varList, List<Boolean> isVarArg,
66+
public Procedure(String name, LeftHandSideType returnType, List<IVariable> varList,
6867
SmartComment procComment,
6968
ParseTree tree, Target t) {
7069
this.name = name;
@@ -96,7 +95,6 @@ public Procedure(String name, CClassType returnType, List<IVariable> varList, Li
9695
//we can be sure that we cannot inline this in any way.
9796
this.possiblyConstant = checkPossiblyConstant(tree);
9897
this.returnType = returnType;
99-
this.isVarArg = isVarArg;
10098
}
10199

102100
private boolean checkPossiblyConstant(ParseTree tree) {
@@ -222,7 +220,7 @@ public Mixed execute(List<Mixed> args, Environment oldEnv, Target t) {
222220
CArray vararg = null;
223221
for(varInd = 0; varInd < args.size(); varInd++) {
224222
Mixed c = args.get(varInd);
225-
arguments.push(c, t);
223+
arguments.push(c, t, env);
226224
if(this.varIndex.size() > varInd
227225
|| (!this.varIndex.isEmpty()
228226
&& this.varIndex.get(this.varIndex.size() - 1).getDefinedType().isVariadicType())) {
@@ -234,7 +232,8 @@ public Mixed execute(List<Mixed> args, Environment oldEnv, Target t) {
234232
var = this.varIndex.get(this.varIndex.size() - 1);
235233
if(vararg == null) {
236234
vararg = new CArray(t, GenericParameters.emptyBuilder(CArray.TYPE)
237-
.addParameter(var.getDefinedType()).build(t, env), env);
235+
.addParameter(var.getDefinedType().getVarargsBaseType(env))
236+
.build(t, env), env);
238237
try {
239238
env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(CArray.TYPE,
240239
var.getVariableName(), vararg, c.getTarget()));
@@ -254,7 +253,7 @@ public Mixed execute(List<Mixed> args, Environment oldEnv, Target t) {
254253

255254
// Type check vararg parameter.
256255
if(var.getDefinedType().isVariadicType()) {
257-
if(InstanceofUtil.isInstanceof(c.typeof(env), var.getDefinedType().getVarargsBaseType(), env)) {
256+
if(InstanceofUtil.isInstanceof(c, var.getDefinedType().getVarargsBaseType(env), env)) {
258257
vararg.push(c, t, env);
259258
continue;
260259
} else {
@@ -265,7 +264,7 @@ public Mixed execute(List<Mixed> args, Environment oldEnv, Target t) {
265264
}
266265

267266
// Type check non-vararg parameter.
268-
if(InstanceofUtil.isInstanceof(c.typeof(env), var.getDefinedType(), env)) {
267+
if(InstanceofUtil.isInstanceof(c, var.getDefinedType(), env)) {
269268
try {
270269
env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(var.getDefinedType(),
271270
var.getVariableName(), c, c.getTarget(), env));
@@ -321,12 +320,12 @@ public Mixed execute(List<Mixed> args, Environment oldEnv, Target t) {
321320
} catch (FunctionReturnException e) {
322321
// Normal exit
323322
Mixed ret = e.getReturn();
324-
if(returnType.equals(Auto.TYPE)) {
323+
if(returnType.equals(Auto.LHSTYPE)) {
325324
return ret;
326325
}
327-
if(returnType.equals(CVoid.TYPE) != ret.equals(CVoid.VOID)
326+
if(returnType.equals(CVoid.TYPE.asLeftHandSideType()) != ret.equals(CVoid.VOID)
328327
|| !ret.equals(CNull.NULL) && !ret.equals(CVoid.VOID)
329-
&& !InstanceofUtil.isInstanceof(ret.typeof(env), returnType, env)) {
328+
&& !InstanceofUtil.isInstanceof(ret, returnType, env)) {
330329
throw new CRECastException("Expected procedure \"" + name + "\" to return a value of type "
331330
+ returnType.val() + " but a value of type " + ret.typeof(env) + " was returned instead",
332331
ret.getTarget());
@@ -351,7 +350,7 @@ public Mixed execute(List<Mixed> args, Environment oldEnv, Target t) {
351350
// If we got here, then there was no return value. This is fine, but only for returnType void or auto.
352351
// TODO: Once strong typing is implemented at a compiler level, this should be removed to increase runtime
353352
// performance.
354-
if(!(returnType.equals(Auto.TYPE) || returnType.equals(CVoid.TYPE))) {
353+
if(!(returnType.equals(Auto.LHSTYPE) || returnType.equals(CVoid.TYPE.asLeftHandSideType()))) {
355354
throw new CRECastException("Expecting procedure \"" + name + "\" to return a value of type " + returnType.val() + ","
356355
+ " but no value was returned.", tree.getTarget());
357356
}
@@ -379,7 +378,7 @@ public void definitelyNotConstant() {
379378
}
380379

381380
public LeftHandSideType getReturnType() {
382-
return returnType.asLeftHandSideType();
381+
return returnType;
383382
}
384383

385384
public List<LeftHandSideType> getParameterTypes() {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.laytonsmith.core;
2+
3+
import com.laytonsmith.core.constructs.CClassType;
4+
import com.laytonsmith.core.constructs.LeftHandSideType;
5+
import com.laytonsmith.core.constructs.Target;
6+
import com.laytonsmith.core.exceptions.CRE.CREIllegalArgumentException;
7+
8+
/**
9+
* A SourceType is a type that can be represented in code.
10+
* @author Cailin
11+
*/
12+
public interface SourceType {
13+
14+
/**
15+
* Returns this type as a LeftHandSideType.
16+
* @return
17+
*/
18+
LeftHandSideType asLeftHandSideType();
19+
20+
/**
21+
* If and only if this was constructed in such a way that it could have been a CClassType to begin with, this
22+
* function will return the CClassType. This is generally useful when converting initially from a CClassType, and
23+
* then getting that value back, however, it can be used anyways if the parameters are such that it's allowed. In
24+
* particular, this cannot be a type union, and the LeftHandGenericUse statement must be null. (There may be
25+
* concrete generic parameters attached to the underlying CClassType though.) If these requirements are not met, a
26+
* CREIllegalArgumentException is thrown.
27+
*
28+
* @param t
29+
* @return
30+
*/
31+
CClassType asConcreteType(Target t) throws CREIllegalArgumentException;
32+
}

src/main/java/com/laytonsmith/core/constructs/Auto.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.laytonsmith.core.constructs;
22

3+
import com.laytonsmith.core.exceptions.ConfigCompileException;
4+
35
/**
46
* Auto is not a real type, but we need a placeholder for a few meta things, such as the CClassType for it.
57
*
@@ -9,4 +11,12 @@ public class Auto {
911

1012
public static final CClassType TYPE = CClassType.AUTO;
1113
public static final LeftHandSideType LHSTYPE = TYPE.asLeftHandSideType();
14+
public static final LeftHandSideType LHSTYPE_VARIADIC;
15+
static {
16+
try {
17+
LHSTYPE_VARIADIC = LHSTYPE.asVariadicType(Target.UNKNOWN, null);
18+
} catch(ConfigCompileException ex) {
19+
throw new Error();
20+
}
21+
}
1222
}

src/main/java/com/laytonsmith/core/constructs/CClassType.java

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.laytonsmith.core.objects.ObjectType;
4040
import com.laytonsmith.core.objects.UserObject;
4141
import com.laytonsmith.PureUtilities.Common.Annotations.AggressiveDeprecation;
42+
import com.laytonsmith.core.SourceType;
4243

4344
import java.net.URL;
4445
import java.util.ArrayList;
@@ -58,6 +59,13 @@
5859
/**
5960
* A CClassType represents a reference to a MethodScript class, which is generally used on the right hand side. See
6061
* {@link LeftHandSideType} for the left hand side equivalent.
62+
* <p>
63+
* There are major differences in how CClassTypes are handled, compared to for instance LeftHandSideTypes.
64+
* For any given class, there can only be one CClassType instance, for any given set of generic parameters.
65+
* CClassType can always be represented as a LeftHandSideType, but there can be multiple LeftHandSideTypes that
66+
* represent the same type - these represent specific usages of the type in certain places in the code, not the
67+
* type itself. For this reason, CClassType cannot represent variadic types, because that is a call site specific
68+
* concept.
6169
*/
6270
@typeof("ms.lang.ClassType")
6371
@SuppressWarnings("checkstyle:overloadmethodsdeclarationorder")
@@ -248,8 +256,6 @@ public Class<? extends Documentation>[] seeAlso() {
248256
private final FullyQualifiedClassName fqcn;
249257
@StandardField
250258
private final GenericTypeParameters genericParameters;
251-
@StandardField
252-
private boolean isVariadicType = false;
253259

254260
/**
255261
* This is an invalid instance of the underlying type that can only be used for Documentation purposes or finding
@@ -848,6 +854,11 @@ public Set<ObjectModifier> getObjectModifiers() {
848854
return EnumSet.of(ObjectModifier.FINAL);
849855
}
850856

857+
public Set<ObjectModifier> getTypeObjectModifiers(Environment env) {
858+
instantiateInvalidType(env);
859+
return invalidType.getObjectModifiers();
860+
}
861+
851862
@Override
852863
public Version since() {
853864
return MSVersion.V3_3_1;
@@ -1068,10 +1079,16 @@ public GenericParameters getGenericParameters() {
10681079
* Converts this concrete type into a LHS type. This will always work, since all concrete types can be
10691080
* represented as LHS types.
10701081
*/
1082+
@Override
10711083
public LeftHandSideType asLeftHandSideType() {
10721084
return LeftHandSideType.fromHardCodedType(this);
10731085
}
10741086

1087+
@Override
1088+
public CClassType asConcreteType(Target t) {
1089+
return this;
1090+
}
1091+
10751092
/**
10761093
* Returns the set of generic parameters for the given superclass, perhaps using the parameters provided to the
10771094
* specific subclass. For instance, if we have {@code class A<T, U> extends B<U>}, and we want to see if the value
@@ -1294,22 +1311,4 @@ private boolean containsNakedClassType(FullyQualifiedClassName fqcn) {
12941311
return contains(fqcn, null);
12951312
}
12961313
}
1297-
1298-
@Override
1299-
public boolean isVariadicType() {
1300-
return isVariadicType;
1301-
}
1302-
1303-
@Override
1304-
public SourceType asVariadicType(Environment env) {
1305-
CClassType newType;
1306-
try {
1307-
newType = new CClassType(this.fqcn.asVariadicType(), getTarget(), false,
1308-
this.genericDeclaration, env, this.nativeClass);
1309-
} catch(ClassNotFoundException ex) {
1310-
throw new Error(ex);
1311-
}
1312-
newType.isVariadicType = true;
1313-
return newType;
1314-
}
13151314
}

src/main/java/com/laytonsmith/core/constructs/CClosure.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ public class CClosure extends Construct implements Callable, Booleanish {
5555
protected final Mixed[] defaults;
5656
protected final LeftHandSideType[] types;
5757
protected final LeftHandSideType returnType;
58-
protected final Boolean[] isVarArgs;
5958

6059
private static final Constraints RETURN_TYPE = new Constraints(Target.UNKNOWN, ConstraintLocation.DEFINITION, new UnboundedConstraint(Target.UNKNOWN, "ReturnType"));
6160
private static final Constraints PARAMETERS = new Constraints(Target.UNKNOWN, ConstraintLocation.DEFINITION, new VariadicTypeConstraint(Target.UNKNOWN, "Parameters"));
@@ -68,14 +67,13 @@ public class CClosure extends Construct implements Callable, Booleanish {
6867
.addParameter("Parameters", PARAMETERS));
6968

7069
public CClosure(ParseTree node, Environment env, LeftHandSideType returnType, String[] names, Mixed[] defaults,
71-
Boolean[] isVarArgs, LeftHandSideType[] types, Target t) {
70+
LeftHandSideType[] types, Target t) {
7271
super(node != null ? node.toString() : "", ConstructType.CLOSURE, t);
7372
this.node = node;
7473
this.env = env;
7574
this.names = names;
7675
this.defaults = defaults;
7776
this.types = types;
78-
this.isVarArgs = isVarArgs;
7977
if(types.length > 0) {
8078
for(int i = 0; i < types.length - 1; i++) {
8179
if(types[i].isVariadicType()) {
@@ -262,21 +260,21 @@ protected void execute(Mixed... values) throws ConfigRuntimeException, ProgramFl
262260
} else {
263261
name = this.names[this.names.length - 1];
264262
if(vararg == null) {
265-
// TODO: Once generics are added, add the type
263+
varargType = this.types[this.types.length - 1].getVarargsBaseType(env);
266264
vararg = new CArray(value.getTarget(), GenericParameters.emptyBuilder(CArray.TYPE)
267-
.addParameter(varargType).build(getTarget(), env), env);
265+
.addParameter(varargType)
266+
.build(getTarget(), env), env);
268267
try {
269268
env.getEnv(GlobalEnv.class).GetVarList().set(new IVariable(CArray.TYPE,
270269
name, vararg, value.getTarget()));
271270
} catch(ConfigCompileException ex) {
272271
throw new CREError(ex.getMessage(), getTarget(), ex);
273272
}
274-
varargType = this.types[this.types.length - 1];
275273
}
276274
isVarArg = true;
277275
}
278276
if(isVarArg) {
279-
if(!InstanceofUtil.isInstanceof(value.typeof(env), varargType.getVarargsBaseType(), env)) {
277+
if(!InstanceofUtil.isInstanceof(value, varargType, env)) {
280278
throw new CRECastException("Expected type " + varargType + " but found " + value.typeof(env),
281279
getTarget());
282280
}

src/main/java/com/laytonsmith/core/constructs/CIClosure.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ public class CIClosure extends CClosure {
3131
.addParameter("Parameters", PARAMETERS));
3232

3333
public CIClosure(ParseTree node, Environment env, LeftHandSideType returnType, String[] names, Mixed[] defaults,
34-
Boolean[] isVarArgs, LeftHandSideType[] types, Target t) {
35-
super(node, env, returnType, names, defaults, isVarArgs, types, t);
34+
LeftHandSideType[] types, Target t) {
35+
super(node, env, returnType, names, defaults, types, t);
3636
}
3737

3838
@Override

0 commit comments

Comments
 (0)