Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
ce133b9
Initial commit of generics
LadyCailin Nov 1, 2021
368e90e
Merge branch 'master' into generics
LadyCailin Nov 1, 2021
5c4344d
Still working on changes to add environment in places
LadyCailin Nov 4, 2021
64fb221
Finish refactoring process
LadyCailin Nov 5, 2021
d521be5
Compiles again
LadyCailin Nov 11, 2021
d431fc2
Move instanceof logic to InstanceofUtil + Fix SA instanceof reference…
Pieter12345 Nov 11, 2021
32d16fc
Merge branch 'master' into genericsTake2
PseudoKnight Dec 3, 2021
b0d46a0
Merge branch 'master' into genericsTake2
PseudoKnight Dec 17, 2021
bcaf404
Additional changes. Mostly code complete, though not working.
LadyCailin Feb 11, 2022
edc959c
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Feb 11, 2022
b737796
Merge branch 'master' into genericsTake2
LadyCailin Feb 13, 2022
958a03b
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Feb 25, 2022
e3825c1
Finish generic constraint validation
LadyCailin Feb 27, 2022
ee55d6a
typeof needs Environment
LadyCailin Mar 3, 2022
239a132
Fix provisonal-build and 2 unit tests
LadyCailin Mar 21, 2022
592ab47
Add LeftHandSideType, and rework generics to fix all unit tests.
LadyCailin Mar 23, 2022
921a0c8
Fix tests
LadyCailin Mar 23, 2022
0465349
Merge branch 'master' into genericsTake2
LadyCailin Mar 24, 2022
6121779
Fix player_command bind
LadyCailin Mar 24, 2022
036b753
Use a static cache for native classes
LadyCailin Mar 24, 2022
ba7ebd5
Add back in more deprecated methods
LadyCailin Mar 24, 2022
668e37e
Add @AggressiveDeprecation annotation
LadyCailin Mar 25, 2022
ab14f00
Readd all no-env methods with AggressiveDeprecation
LadyCailin Mar 29, 2022
5d5ba81
Fix javadoc
LadyCailin Mar 29, 2022
809a724
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Mar 29, 2022
8ca78e4
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Mar 30, 2022
89aba77
Change return type and parameter of merged code
LadyCailin Mar 30, 2022
7a09ff0
Update syntax in NewObjects
LadyCailin Mar 30, 2022
23cd8f5
Fix null assignments
LadyCailin Mar 31, 2022
c68d103
Apply changes based on PR comments
LadyCailin Mar 31, 2022
b70b209
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Mar 31, 2022
b9aae16
Bugfixes
LadyCailin Mar 31, 2022
265949e
Fix and() function signature
Pieter12345 Mar 31, 2022
32f2d4a
Cache ClassMirror's JVM name
LadyCailin Apr 1, 2022
f861f77
Merge branch 'genericsTake2' of github.com:EngineHub/CommandHelper in…
LadyCailin Apr 1, 2022
24117ca
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Apr 1, 2022
26151e4
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Apr 2, 2022
cde5f4c
Pass GenericParameters in to functions.
LadyCailin Apr 2, 2022
0a6bd55
Also convert leftover test method
LadyCailin Apr 2, 2022
f40c67d
Provide runtime backwards compatible Event for extensions
LadyCailin Apr 2, 2022
2510cf2
CS
LadyCailin Apr 2, 2022
5b645c1
Merge branch 'master' into genericsTake2
LadyCailin Apr 3, 2022
8438464
Add back old CArray constructors as aggressively deprecated
LadyCailin Apr 3, 2022
9aab1c1
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Apr 3, 2022
4327ee0
Rework how generics are stored in Construct
LadyCailin Apr 3, 2022
aa5bc2c
Support GenericDeclaration in function signatures
LadyCailin Apr 3, 2022
6ba3f82
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Apr 4, 2022
6dc811d
Remove erroneous code
LadyCailin Apr 4, 2022
ee4379c
Better error message
LadyCailin Apr 4, 2022
5bc8cc0
Resolve typename before returning up further.
LadyCailin Apr 5, 2022
ab74ad2
Unbundle and rethrow CREs in exec when using reflection
LadyCailin Apr 5, 2022
205e3b3
Add more AggressiveDeprecations.
LadyCailin Apr 5, 2022
ef358b7
Merge branch 'master' into genericsTake2
LadyCailin Apr 6, 2022
f18e0f8
Add aggressivedeprecation on IncludeCache.registerAutoIncludes
LadyCailin Apr 6, 2022
37d1ed4
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Apr 6, 2022
c8221fa
Add deprecated versions of set back to CArray
LadyCailin Apr 6, 2022
f0faa0b
Oops
LadyCailin Apr 6, 2022
5516d5e
Remove registerAutoIncludes
LadyCailin Apr 6, 2022
722495f
Add a log output if the aggressive deprecation meets criteria for rem…
LadyCailin Apr 6, 2022
e42666e
cleanup
LadyCailin Apr 7, 2022
8ad1434
Allow "teeing up" of aggressive deprecations.
LadyCailin Apr 7, 2022
85ed2f4
Support type inference for generic typenames
LadyCailin Apr 10, 2022
9900ee1
CS
LadyCailin Apr 11, 2022
0e3667f
Add cast().
LadyCailin Apr 11, 2022
082cd9b
CS
LadyCailin Apr 11, 2022
28a037a
Speculative fix for reported issue
LadyCailin Apr 12, 2022
f658e57
Add additional unit tests
LadyCailin Apr 12, 2022
f091c99
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Apr 12, 2022
909efe8
Missed a change
LadyCailin Apr 12, 2022
c6834b2
Use the correct SA object
LadyCailin Apr 12, 2022
1726fd2
cs
LadyCailin Apr 12, 2022
0d78170
Speculative fix and additional logging
LadyCailin Apr 13, 2022
94910ec
Resolve type unions also, for when there is only one inferred type
LadyCailin Apr 13, 2022
0a2b7d3
cs
LadyCailin Apr 13, 2022
7a9ffe8
Fix centry typechecking
LadyCailin Apr 13, 2022
b0af7fd
cs
LadyCailin Apr 13, 2022
8f1a8a0
Make constants their actual type in strict mode, auto otherwise.
LadyCailin Apr 14, 2022
7e00c25
Merge branch 'master' into genericsTake2
LadyCailin Apr 19, 2022
f0f9a6c
Merge branch 'master' into genericsTake2
LadyCailin Apr 19, 2022
3cd8334
dev drop
LadyCailin Apr 22, 2022
d376ad5
Merge branch 'master' into genericsTake2
LadyCailin Apr 22, 2022
8d15bee
Create GenericTypeParameters, which are the typechecking generics
LadyCailin Apr 27, 2022
3817ae9
Merge branch 'master' into genericsTake2
LadyCailin Apr 27, 2022
5fc3192
URL encode spaces in ClassMirror
LadyCailin Apr 27, 2022
48d21b6
Use proper URL escaping
LadyCailin Apr 27, 2022
641a316
Revert "Use proper URL escaping"
LadyCailin Apr 27, 2022
031e0ad
Maybe fixed now
LadyCailin Apr 27, 2022
97ff952
Add asserts to track down failures
LadyCailin Apr 27, 2022
957f176
Decode that shit
LadyCailin Apr 27, 2022
535f9bc
Cleanup build output and clarify logs
LadyCailin Apr 27, 2022
44fe145
Merge branch 'master' into genericsTake2
LadyCailin Apr 28, 2022
8488d39
Merge branch 'master' into genericsTake2
LadyCailin May 5, 2022
1131858
Add support for `as` keyword for cast.
LadyCailin May 5, 2022
2946044
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin May 5, 2022
937576b
Begin initial implementation of VariadicGenericTypes.
LadyCailin May 6, 2022
0f91e3f
Merge branch 'master' into genericsTake2
LadyCailin May 7, 2022
199b33b
Implement generics in Callables.
LadyCailin May 8, 2022
78eb89a
Merge branch 'master' into genericsTake2
PseudoKnight Jun 15, 2022
f5aeffb
Merge branch 'master' into genericsTake2
PseudoKnight Jul 5, 2022
1cade80
Merge remote-tracking branch 'origin/master' into genericsTake2
LadyCailin Jan 9, 2023
0f3dc21
Merge branch 'master' into genericsTake2
LadyCailin Sep 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make constants their actual type in strict mode, auto otherwise.
This changes the declared type (not to be confused with the actual type)
of constants to auto in non-strict mode, and their actual types in
strict mode. This is necessary, because currently, code such as `'123' >
10` is supported, and needs to continue to be supported into the future.
However, adding typechecking to functions will start to break this code,
which is undesireable. Therefore, in non-strict mode, constants will be
declared as type auto.

Additionally, for functions that end up matching multiple signatures,
instead of returning the type union for possible return values, it now
returns auto, if any of the parameters are auto. This prevents further
type errors up the chain when signatures might be ambiguous. For
instance, if we have both array func(int) and int func(string), then in
non-strict mode, `func(@auto)` would be ambiguous. However, since the
parameter is auto, the user has already indicated that they are ok with
deferring typechecking until runtime anyways, so we prevent requiring a
cast in this case by returning auto, so `array @A = func(@auto)` will
also continue to work with no casts. This behavior is the same in both
strict and non-strict mode, but is more likely to be triggered in
non-strict mode due to the fact that constants are auto.

A few bugs were fixed with strict mode and centry, as well as when
unknonwn functions are found in certain cases.
  • Loading branch information
LadyCailin committed Apr 14, 2022
commit 8f1a8a05893e7368f077fe03fb08457d1de7b1e3
33 changes: 25 additions & 8 deletions src/main/java/com/laytonsmith/core/ParseTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -421,15 +421,17 @@ public Target getTarget() {
* be AUTO. The type may be CNull for literal nulls, but will never be java null.
*
* @param sa The static analysis object.
* @param t The code target, used for exceptions for ambiguous matches.
* @param env The environment
* @param inferredType The inferred type, if this is a function call. Otherwise, can be null.
* @return
*/
public LeftHandSideType getDeclaredType(StaticAnalysis sa, Target t, Environment env, LeftHandSideType inferredType) {
public LeftHandSideType getDeclaredType(StaticAnalysis sa, Environment env, LeftHandSideType inferredType) {
if(isConst()) {
return Auto.LHSTYPE;
// return getData().typeof(env).asLeftHandSideType();
if(!getFileOptions().isStrict()) {
return Auto.LHSTYPE;
} else {
return getData().typeof(env).asLeftHandSideType();
}
} else if(getData() instanceof IVariable ivar) {
if(sa.isLocalEnabled()) {
Scope scope = sa.getTermScope(this);
Expand Down Expand Up @@ -465,17 +467,32 @@ public LeftHandSideType getDeclaredType(StaticAnalysis sa, Target t, Environment
} else {
List<Target> argTargets = new ArrayList<>();
Set<ConfigCompileException> exceptions = new HashSet<>();
List<LeftHandSideType> argTypes = cf.getCachedFunction()
.getResolvedParameterTypes(sa, t, env, this.getNodeModifiers().getGenerics(),
inferredType, getChildren());
List<LeftHandSideType> argTypes;
try {
if(cf.getCachedFunction() == null) {
// Function doesn't exist, just make everything auto so that the rest of typechecking
// can continue running.
return Auto.LHSTYPE;
} else {
argTypes = cf.getFunction()
.getResolvedParameterTypes(sa, getTarget(), env, this.getNodeModifiers().getGenerics(),
inferredType, getChildren());
}
} catch(ConfigCompileException ex) {
throw new RuntimeException(getTarget().toString(), ex);
}
for(ParseTree child : getChildren()) {
argTargets.add(child.getTarget());
}
return cf.getCachedFunction().getReturnType(this, getTarget(),
argTypes, argTargets, inferredType, env, exceptions);
}
} else if(getData() instanceof Variable) {
return Auto.LHSTYPE;
if(getFileOptions().isStrict()) {
return CString.TYPE.asLeftHandSideType();
} else {
return Auto.LHSTYPE;
}
} else {
throw new Error("Unhandled type, please report this bug. Caused by code from " + getTarget());
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/laytonsmith/core/asm/LLVMFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public List<LeftHandSideType> getResolvedParameterTypes(StaticAnalysis analysis,
return generics.getLeftHandParameters();
}
for(ParseTree child : children) {
ret.add(child.getDeclaredType(analysis, t, env, Auto.LHSTYPE));
ret.add(child.getDeclaredType(analysis, env, Auto.LHSTYPE));
}
return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.laytonsmith.core.constructs.CFunction;
import com.laytonsmith.core.constructs.CKeyword;
import com.laytonsmith.core.constructs.CLabel;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.IVariable;
import com.laytonsmith.core.constructs.InstanceofUtil;
import com.laytonsmith.core.constructs.LeftHandSideType;
Expand Down Expand Up @@ -427,7 +428,11 @@ public LeftHandSideType typecheck(ParseTree ast, LeftHandSideType inferredReturn
return LeftHandSideType.fromCClassType(CClassType.AUTO, Target.UNKNOWN);
}
} else if(node instanceof Variable) {
return Auto.LHSTYPE;
if(ast.getFileOptions().isStrict()) {
return CString.TYPE.asLeftHandSideType();
} else {
return Auto.LHSTYPE;
}
} else if(node instanceof CKeyword) {

// Use the more specific compile error caused during keyword processing if available.
Expand All @@ -443,7 +448,8 @@ public LeftHandSideType typecheck(ParseTree ast, LeftHandSideType inferredReturn
}

// The node is some other Construct, so return its type.
if(ast.isConst()) {
// In non-strict mode, constants are defined as auto, to make things like `'123' > 10` work.
if(ast.isConst() && !ast.getFileOptions().isStrict()) {
return Auto.LHSTYPE;
}
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import com.laytonsmith.PureUtilities.Common.StringUtils;
import com.laytonsmith.core.ParseTree;
import com.laytonsmith.core.constructs.Auto;
import com.laytonsmith.core.constructs.CClassType;
import com.laytonsmith.core.constructs.LeftHandSideType;
import com.laytonsmith.core.constructs.Target;
Expand Down Expand Up @@ -120,21 +121,29 @@ public LeftHandSideType getReturnType(ParseTree node, Target t, List<LeftHandSid
typeResolutions);
}
default -> {
// TODO - Ideally, we'd either return a multi-type or the most specific super type of the signatures.
// Return the return type of all matching signatures if they are the same.
LeftHandSideType type = LeftHandSideType.resolveTypeFromGenerics(t, env, matches.get(0).getReturnType().getType(),
generics,
matches.get(0).getGenericDeclaration(), inferredReturnType);
for(int i = 1; i < matches.size(); i++) {
LeftHandSideType[] types = new LeftHandSideType[matches.size()];
for(int i = 0; i < matches.size(); i++) {
LeftHandSideType retType = LeftHandSideType.resolveTypeFromGenerics(t, env,
matches.get(i).getReturnType().getType(),
generics,
matches.get(0).getGenericDeclaration(), inferredReturnType);
if((retType == null ? retType != type : !retType.equals(type))) {
return CClassType.AUTO.asLeftHandSideType();
types[i] = retType;
}
LeftHandSideType ret = LeftHandSideType.createTypeUnion(t, types);
if(ret.isTypeUnion()) {
// If multiple types match, and one or more of the arguments is auto, we return auto, rather than
// the type union. This indicates that the user is content with runtime type verification, and so
// we continue that up the chain. In non-strict mode, constants (and $vars) are declared as auto,
// so that we get expected behavior with for instance `'123' > 10`, which causes this mode to be
// triggered more often than in non-strict mode. For non-ambiguous signatures even with auto arguments,
// this behavior is not triggered.
for(LeftHandSideType argType : argTypes) {
if(Auto.LHSTYPE.equals(argType)) {
return Auto.LHSTYPE;
}
}
}
return type;
return ret;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,11 @@ public static CClassType get(CClassType nakedType, Target t, Map<CClassType, Gen
* provided, then this will be thrown.
*/
public static CClassType get(Class<? extends Mixed> type, Target t, Map<CClassType, GenericParameters> generics, Environment env) {
return get(FullyQualifiedClassName.forNativeClass(type), t, generics, env);
try {
return get(FullyQualifiedClassName.forNativeClass(type), t, generics, env);
} catch(Error e) {
throw new Error(e.getMessage() + " Caused by code around " + t.toString(), e);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ public CClassType typeof(Environment env) {
* @return
*/
public static CClassType typeof(Mixed that, Environment env) {
return CClassType.get(that.getClass(), Target.UNKNOWN, that.getGenericParameters(), env);
return CClassType.get(that.getClass(), that.getTarget(), that.getGenericParameters(), env);
}

private final Map<CClassType, GenericParameters> genericParameters = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public List<LeftHandSideType> getResolvedParameterTypes(StaticAnalysis analysis,
return generics.getLeftHandParameters();
}
for(ParseTree child : children) {
ret.add(child.getDeclaredType(analysis, t, env, Auto.LHSTYPE));
ret.add(child.getDeclaredType(analysis, env, Auto.LHSTYPE));
}
return ret;
// if(signatures == null) {
Expand Down Expand Up @@ -208,7 +208,7 @@ public LeftHandSideType typecheck(StaticAnalysis analysis,
List<LeftHandSideType> argTypes = new ArrayList<>(children.size());
List<Target> argTargets = new ArrayList<>(children.size());
for(ParseTree child : children) {
LeftHandSideType inferredParameterType = child.getDeclaredType(analysis, ast.getTarget(), env, Auto.LHSTYPE);
LeftHandSideType inferredParameterType = child.getDeclaredType(analysis, env, Auto.LHSTYPE);
inferredParameterType = LeftHandSideType.resolveTypeFromGenerics(Target.UNKNOWN, env, inferredParameterType, null, null, (Map) null);
argTypes.add(analysis.typecheck(child, inferredParameterType, env, exceptions));
argTargets.add(child.getTarget());
Expand Down
18 changes: 17 additions & 1 deletion src/main/java/com/laytonsmith/core/functions/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,26 @@ public LeftHandSideType typecheck(StaticAnalysis analysis,
exceptions.add(new ConfigCompileException("Expected label.", ast.getChildAt(0).getTarget()));
}
LeftHandSideType inferredParameterType = ast.getChildAt(1)
.getDeclaredType(analysis, ast.getTarget(), env, Auto.LHSTYPE);
.getDeclaredType(analysis, env, Auto.LHSTYPE);
inferredParameterType = LeftHandSideType.resolveTypeFromGenerics(Target.UNKNOWN, env, inferredParameterType, null, null, (Map) null);
return analysis.typecheck(ast.getChildAt(1), inferredParameterType, env, exceptions);
}

@Override
public List<LeftHandSideType> getResolvedParameterTypes(StaticAnalysis analysis, Target t, Environment env, GenericParameters generics, LeftHandSideType inferredReturnType, List<ParseTree> children) {
List<LeftHandSideType> ret = new ArrayList<>();
ret.add(Auto.LHSTYPE);
ret.add(children.get(1).getDeclaredType(analysis, env, inferredReturnType));
return ret;
}

@Override
public LeftHandSideType getReturnType(ParseTree node, Target t, List<LeftHandSideType> argTypes, List<Target> argTargets, LeftHandSideType inferredReturnType, Environment env, Set<ConfigCompileException> exceptions) {
return argTypes.get(1);
}



}

@api
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1303,14 +1303,13 @@ public void testParseTreeHasCorrectType() throws Exception {
ParseTree tree = MethodScriptCompiler.compile(MethodScriptCompiler.lex("primitive @s = 'asdf'; msg(@s); int proc _a(){return(1);} _a();",
env, null, true), env, env.getEnvClasses(), sa);
ParseTree sUsage = tree.getChildAt(0).getChildAt(1).getChildAt(0);
Target t = Target.UNKNOWN;
assertTrue(sUsage.getDeclaredType(sa, t, env, null).equals(CPrimitive.TYPE.asLeftHandSideType()));
assertTrue(sUsage.getDeclaredType(sa, env, null).equals(CPrimitive.TYPE.asLeftHandSideType()));
ParseTree asdf = tree.getChildAt(0).getChildAt(0).getChildAt(2);
assertTrue(asdf.getDeclaredType(sa, t, env, null).equals(Auto.LHSTYPE));
assertTrue(asdf.getDeclaredType(sa, env, null).equals(Auto.LHSTYPE));
ParseTree msg = tree.getChildAt(0).getChildAt(1);
assertTrue(msg.getDeclaredType(sa, t, env, null).equals(CVoid.TYPE.asLeftHandSideType()));
assertTrue(msg.getDeclaredType(sa, env, null).equals(CVoid.TYPE.asLeftHandSideType()));
ParseTree _a = tree.getChildAt(0).getChildAt(3);
assertTrue(_a.getDeclaredType(sa, t, env, null).equals(CInt.TYPE.asLeftHandSideType()));
assertTrue(_a.getDeclaredType(sa, env, null).equals(CInt.TYPE.asLeftHandSideType()));
}

@Test
Expand Down
19 changes: 15 additions & 4 deletions src/test/java/com/laytonsmith/core/StaticAnalysisTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,16 @@ public void testRecursiveTypeInferrenceWorks() throws Exception {
ParseTree tree = saScript("string @r = 'string'; string @s = dyn(dyn(dyn(dyn(dyn(@r)))));");
ParseTree topDynNode = tree.getChildAt(0).getChildAt(1).getChildAt(2);
Assert.assertEquals(CString.TYPE.asLeftHandSideType(),
topDynNode.getDeclaredType(staticAnalysis, Target.UNKNOWN, env, null));
topDynNode.getDeclaredType(staticAnalysis, env, null));
Assert.assertEquals(CString.TYPE.asLeftHandSideType(),
topDynNode.getDeclaredType(staticAnalysis, Target.UNKNOWN, env, CString.TYPE.asLeftHandSideType()));
topDynNode.getDeclaredType(staticAnalysis, env, CString.TYPE.asLeftHandSideType()));
// This is auto, because constants are auto typed.
tree = saScript("string @s = dyn(dyn(dyn(dyn(dyn('string')))));");
topDynNode = tree.getChildAt(0).getChildAt(2);
Assert.assertEquals(Auto.LHSTYPE,
topDynNode.getDeclaredType(staticAnalysis, Target.UNKNOWN, env, null));
topDynNode.getDeclaredType(staticAnalysis, env, null));
Assert.assertEquals(Auto.LHSTYPE,
topDynNode.getDeclaredType(staticAnalysis, Target.UNKNOWN, env, CString.TYPE.asLeftHandSideType()));
topDynNode.getDeclaredType(staticAnalysis, env, CString.TYPE.asLeftHandSideType()));

saScriptExpectException("string @s = dyn(dyn(dyn(array())));");
}
Expand Down Expand Up @@ -218,4 +218,15 @@ public void testLabels() throws Exception {
saScript("array @a = array(label: 'goes', here: 'too'); msg(@a);");
}

@Test
public void testLabelsWithStrictMode() throws Exception {
saScript("<!strict> assign(@w, array('world': 'overworld', 'world_nether': 'nether', 'world_the_end': 'end'))");
}

@Test
public void testVariablesInStrictMode() throws Exception {
saScriptExpectException("<! strict > if($var > 1) { msg(''); }");
saScript("if($var > 1) { msg(''); }");
}

}