brighterscript 1.0.0-alpha.47 → 1.0.0-alpha.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +7 -10
  2. package/bsconfig.schema.json +34 -7
  3. package/dist/AstValidationSegmenter.js +21 -3
  4. package/dist/AstValidationSegmenter.js.map +1 -1
  5. package/dist/BsConfig.d.ts +6 -35
  6. package/dist/CrossScopeValidator.d.ts +1 -0
  7. package/dist/CrossScopeValidator.js +28 -4
  8. package/dist/CrossScopeValidator.js.map +1 -1
  9. package/dist/DiagnosticMessages.d.ts +1 -1
  10. package/dist/DiagnosticMessages.js +20 -6
  11. package/dist/DiagnosticMessages.js.map +1 -1
  12. package/dist/LanguageServer.d.ts +22 -6
  13. package/dist/LanguageServer.js +62 -25
  14. package/dist/LanguageServer.js.map +1 -1
  15. package/dist/PluginInterface.js +4 -1
  16. package/dist/PluginInterface.js.map +1 -1
  17. package/dist/Program.d.ts +9 -3
  18. package/dist/Program.js +111 -74
  19. package/dist/Program.js.map +1 -1
  20. package/dist/ProgramBuilder.d.ts +0 -2
  21. package/dist/ProgramBuilder.js +10 -28
  22. package/dist/ProgramBuilder.js.map +1 -1
  23. package/dist/SymbolTable.js +3 -2
  24. package/dist/SymbolTable.js.map +1 -1
  25. package/dist/astUtils/reflection.d.ts +14 -2
  26. package/dist/astUtils/reflection.js +70 -18
  27. package/dist/astUtils/reflection.js.map +1 -1
  28. package/dist/astUtils/visitors.d.ts +2 -1
  29. package/dist/astUtils/visitors.js.map +1 -1
  30. package/dist/bscPlugin/CallExpressionInfo.js +9 -3
  31. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -1
  32. package/dist/bscPlugin/completions/CompletionsProcessor.js +3 -0
  33. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  34. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +34 -1
  35. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
  36. package/dist/bscPlugin/hover/HoverProcessor.spec.js +31 -0
  37. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  38. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +10 -4
  39. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  40. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +17 -0
  41. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  42. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +5 -0
  43. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +71 -3
  44. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -1
  45. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +7 -7
  46. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -1
  47. package/dist/bscPlugin/validation/BrsFileValidator.js +43 -14
  48. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  49. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +99 -0
  50. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  51. package/dist/bscPlugin/validation/ScopeValidator.d.ts +1 -0
  52. package/dist/bscPlugin/validation/ScopeValidator.js +19 -4
  53. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  54. package/dist/bscPlugin/validation/ScopeValidator.spec.js +372 -0
  55. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  56. package/dist/cli.js +11 -18
  57. package/dist/cli.js.map +1 -1
  58. package/dist/files/BrsFile.Class.spec.js +336 -200
  59. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  60. package/dist/files/BrsFile.spec.js +168 -10
  61. package/dist/files/BrsFile.spec.js.map +1 -1
  62. package/dist/files/XmlFile.d.ts +7 -0
  63. package/dist/files/XmlFile.js +36 -0
  64. package/dist/files/XmlFile.js.map +1 -1
  65. package/dist/files/XmlFile.spec.js +7 -9
  66. package/dist/files/XmlFile.spec.js.map +1 -1
  67. package/dist/files/tests/imports.spec.js +3 -3
  68. package/dist/files/tests/imports.spec.js.map +1 -1
  69. package/dist/files/tests/optionalChaning.spec.js +1 -1
  70. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  71. package/dist/interfaces.d.ts +12 -4
  72. package/dist/interfaces.js.map +1 -1
  73. package/dist/lexer/Lexer.spec.js +12 -2
  74. package/dist/lexer/Lexer.spec.js.map +1 -1
  75. package/dist/lexer/TokenKind.js +6 -3
  76. package/dist/lexer/TokenKind.js.map +1 -1
  77. package/dist/lsp/LspProject.d.ts +17 -9
  78. package/dist/lsp/Project.d.ts +8 -7
  79. package/dist/lsp/Project.js +21 -23
  80. package/dist/lsp/Project.js.map +1 -1
  81. package/dist/lsp/Project.spec.js +44 -12
  82. package/dist/lsp/Project.spec.js.map +1 -1
  83. package/dist/lsp/ProjectManager.d.ts +31 -10
  84. package/dist/lsp/ProjectManager.js +130 -60
  85. package/dist/lsp/ProjectManager.js.map +1 -1
  86. package/dist/lsp/ProjectManager.spec.js +245 -115
  87. package/dist/lsp/ProjectManager.spec.js.map +1 -1
  88. package/dist/lsp/worker/WorkerThreadProject.d.ts +6 -7
  89. package/dist/lsp/worker/WorkerThreadProject.js +27 -21
  90. package/dist/lsp/worker/WorkerThreadProject.js.map +1 -1
  91. package/dist/lsp/worker/WorkerThreadProject.spec.js +4 -1
  92. package/dist/lsp/worker/WorkerThreadProject.spec.js.map +1 -1
  93. package/dist/lsp/worker/run.d.ts +1 -0
  94. package/dist/lsp/worker/run.js +14 -0
  95. package/dist/lsp/worker/run.js.map +1 -0
  96. package/dist/parser/AstNode.d.ts +8 -1
  97. package/dist/parser/AstNode.js +9 -0
  98. package/dist/parser/AstNode.js.map +1 -1
  99. package/dist/parser/AstNode.spec.js +1 -1
  100. package/dist/parser/AstNode.spec.js.map +1 -1
  101. package/dist/parser/Expression.d.ts +43 -0
  102. package/dist/parser/Expression.js +120 -7
  103. package/dist/parser/Expression.js.map +1 -1
  104. package/dist/parser/Parser.Class.spec.js +25 -0
  105. package/dist/parser/Parser.Class.spec.js.map +1 -1
  106. package/dist/parser/Parser.d.ts +4 -0
  107. package/dist/parser/Parser.js +117 -7
  108. package/dist/parser/Parser.js.map +1 -1
  109. package/dist/parser/Parser.spec.js +200 -1
  110. package/dist/parser/Parser.spec.js.map +1 -1
  111. package/dist/parser/Statement.d.ts +32 -1
  112. package/dist/parser/Statement.js +128 -64
  113. package/dist/parser/Statement.js.map +1 -1
  114. package/dist/parser/tests/statement/ConstStatement.spec.js +238 -0
  115. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  116. package/dist/roku-types/data.json +422 -64
  117. package/dist/roku-types/index.d.ts +50 -0
  118. package/dist/types/ArrayType.js +3 -0
  119. package/dist/types/ArrayType.js.map +1 -1
  120. package/dist/types/BscType.d.ts +4 -3
  121. package/dist/types/BscType.js +2 -4
  122. package/dist/types/BscType.js.map +1 -1
  123. package/dist/types/BscTypeKind.d.ts +2 -0
  124. package/dist/types/BscTypeKind.js +2 -0
  125. package/dist/types/BscTypeKind.js.map +1 -1
  126. package/dist/types/CallFuncableType.d.ts +24 -0
  127. package/dist/types/CallFuncableType.js +91 -0
  128. package/dist/types/CallFuncableType.js.map +1 -0
  129. package/dist/types/ComponentType.d.ts +3 -15
  130. package/dist/types/ComponentType.js +2 -56
  131. package/dist/types/ComponentType.js.map +1 -1
  132. package/dist/types/DoubleType.js +1 -1
  133. package/dist/types/DoubleType.js.map +1 -1
  134. package/dist/types/FloatType.js +1 -1
  135. package/dist/types/FloatType.js.map +1 -1
  136. package/dist/types/InlineInterfaceType.d.ts +5 -0
  137. package/dist/types/InlineInterfaceType.js +17 -0
  138. package/dist/types/InlineInterfaceType.js.map +1 -0
  139. package/dist/types/IntegerType.js +1 -1
  140. package/dist/types/IntegerType.js.map +1 -1
  141. package/dist/types/InterfaceType.d.ts +2 -2
  142. package/dist/types/InterfaceType.js +5 -4
  143. package/dist/types/InterfaceType.js.map +1 -1
  144. package/dist/types/LongIntegerType.js +1 -1
  145. package/dist/types/LongIntegerType.js.map +1 -1
  146. package/dist/types/ObjectType.d.ts +1 -0
  147. package/dist/types/ObjectType.js +3 -0
  148. package/dist/types/ObjectType.js.map +1 -1
  149. package/dist/types/ReferenceType.d.ts +3 -2
  150. package/dist/types/ReferenceType.js +54 -22
  151. package/dist/types/ReferenceType.js.map +1 -1
  152. package/dist/types/TypeStatementType.d.ts +18 -0
  153. package/dist/types/TypeStatementType.js +45 -0
  154. package/dist/types/TypeStatementType.js.map +1 -0
  155. package/dist/types/UnionType.d.ts +3 -0
  156. package/dist/types/UnionType.js +7 -0
  157. package/dist/types/UnionType.js.map +1 -1
  158. package/dist/types/UnionType.spec.js +43 -0
  159. package/dist/types/UnionType.spec.js.map +1 -1
  160. package/dist/types/roFunctionType.d.ts +11 -0
  161. package/dist/types/roFunctionType.js +37 -0
  162. package/dist/types/roFunctionType.js.map +1 -0
  163. package/dist/types/roFunctionType.spec.d.ts +1 -0
  164. package/dist/types/roFunctionType.spec.js +20 -0
  165. package/dist/types/roFunctionType.spec.js.map +1 -0
  166. package/dist/util.d.ts +9 -94
  167. package/dist/util.js +67 -305
  168. package/dist/util.js.map +1 -1
  169. package/dist/validators/ClassValidator.js +1 -1
  170. package/dist/validators/ClassValidator.js.map +1 -1
  171. package/package.json +3 -3
@@ -14,6 +14,7 @@ const fsExtra = require("fs-extra");
14
14
  const testHelpers_spec_2 = require("../../testHelpers.spec");
15
15
  const reflection_1 = require("../../astUtils/reflection");
16
16
  const ScopeValidator_1 = require("./ScopeValidator");
17
+ const logger_1 = require("@rokucommunity/logger");
17
18
  describe('ScopeValidator', () => {
18
19
  let sinon = sinonImport.createSandbox();
19
20
  let program;
@@ -1713,6 +1714,86 @@ describe('ScopeValidator', () => {
1713
1714
  ]);
1714
1715
  });
1715
1716
  });
1717
+ describe('inline interfaces', () => {
1718
+ it('allows function param with compatible interface', () => {
1719
+ program.setFile('source/main.bs', `
1720
+ sub takesInline(datum as {name as string})
1721
+ end sub
1722
+
1723
+ sub callsTakesInline()
1724
+ takesInline({age: 123, name: "test"})
1725
+ end sub
1726
+ `);
1727
+ program.validate();
1728
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1729
+ });
1730
+ it('validates function param with incompatible interface', () => {
1731
+ program.setFile('source/main.bs', `
1732
+ sub takesInline(datum as {name as string})
1733
+ end sub
1734
+
1735
+ sub callsTakesInline()
1736
+ takesInline({name: 123})
1737
+ end sub
1738
+ `);
1739
+ program.validate();
1740
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1741
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', '{name as string}', {
1742
+ fieldMismatches: [{ name: 'name', expectedType: StringType_1.StringType.instance, actualType: IntegerType_1.IntegerType.instance }]
1743
+ }).message
1744
+ ]);
1745
+ });
1746
+ });
1747
+ describe('type statement types', () => {
1748
+ it('allows compatible type statement types to be passed to functions expecting normal types', () => {
1749
+ program.setFile('source/main.bs', `
1750
+ type number = integer or float
1751
+
1752
+ sub takesNumber(x as number)
1753
+ takesInteger(x)
1754
+ end sub
1755
+
1756
+ sub takesInteger(x as integer)
1757
+ print x
1758
+ end sub
1759
+ `);
1760
+ program.validate();
1761
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1762
+ });
1763
+ it('disallows incompatible type statement types to be passed to functions expecting normal types', () => {
1764
+ program.setFile('source/main.bs', `
1765
+ type whatever = float or string
1766
+
1767
+ sub takesNumber(x as whatever)
1768
+ takesInteger(x)
1769
+ end sub
1770
+
1771
+ sub takesInteger(x as integer)
1772
+ print x
1773
+ end sub
1774
+ `);
1775
+ program.validate();
1776
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1777
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('whatever', 'integer').message
1778
+ ]);
1779
+ });
1780
+ });
1781
+ it('allows using invalid as argument for typed array params', () => {
1782
+ program.setFile('source/main.bs', `
1783
+ sub takesIntArray(arr as integer[])
1784
+ end sub
1785
+
1786
+ sub takesStrArray(arr as string[])
1787
+ end sub
1788
+
1789
+ sub test()
1790
+ takesIntArray(invalid)
1791
+ takesStrArray(invalid)
1792
+ end sub
1793
+ `);
1794
+ program.validate();
1795
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1796
+ });
1716
1797
  });
1717
1798
  describe('cannotFindName', () => {
1718
1799
  it('finds variables from assignments from member functions of primitive types', () => {
@@ -2178,6 +2259,42 @@ describe('ScopeValidator', () => {
2178
2259
  program.validate();
2179
2260
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2180
2261
  });
2262
+ it('validates accessing a bad member on a type statement type', () => {
2263
+ program.setFile('source/main.bs', `
2264
+ type numberOrString = integer or string
2265
+
2266
+ function test(x as numberOrString)
2267
+ print x.nonExistentMember
2268
+ end function
2269
+ `);
2270
+ program.validate();
2271
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2272
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('nonExistentMember', 'numberOrString.nonExistentMember', 'numberOrString')
2273
+ ]);
2274
+ });
2275
+ describe('inline interfaces', () => {
2276
+ it('finds members of inline interface', () => {
2277
+ program.setFile('source/main.bs', `
2278
+ sub takesInline(datum as {name as string})
2279
+ print datum.name.split(",")
2280
+ end sub
2281
+
2282
+ `);
2283
+ program.validate();
2284
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2285
+ });
2286
+ it('validates using invalid member name', () => {
2287
+ program.setFile('source/main.bs', `
2288
+ sub takesInline(datum as {name as string})
2289
+ print datum.notThere.split(",")
2290
+ end sub
2291
+ `);
2292
+ program.validate();
2293
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2294
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('notThere', '{name as string}.notThere', '{name as string}')
2295
+ ]);
2296
+ });
2297
+ });
2181
2298
  });
2182
2299
  describe('itemCannotBeUsedAsVariable', () => {
2183
2300
  it('detects assigning to a member of a namespace outside the namespace', () => {
@@ -2693,6 +2810,124 @@ describe('ScopeValidator', () => {
2693
2810
  program.validate();
2694
2811
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2695
2812
  });
2813
+ it('allows returning a function call', () => {
2814
+ const spy = sinon.spy(logger_1.Logger.prototype, 'error');
2815
+ program.setFile('source/main.bs', `
2816
+ function abc(func as function) as dynamic
2817
+ return func()
2818
+ end function
2819
+ `);
2820
+ program.validate();
2821
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2822
+ (0, chai_1.expect)(spy.getCalls().map(x => { var _a, _b; return (_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toString(); }).filter(x => x === null || x === void 0 ? void 0 : x.includes('Error when calling plugin'))).to.eql([]);
2823
+ });
2824
+ it('allows returning a roFunction call', () => {
2825
+ const spy = sinon.spy(logger_1.Logger.prototype, 'error');
2826
+ program.setFile('source/main.bs', `
2827
+ function abc(func as roFunction) as dynamic
2828
+ return func()
2829
+ end function
2830
+ `);
2831
+ program.validate();
2832
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2833
+ (0, chai_1.expect)(spy.getCalls().map(x => { var _a, _b; return (_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toString(); }).filter(x => x === null || x === void 0 ? void 0 : x.includes('Error when calling plugin'))).to.eql([]);
2834
+ });
2835
+ it('allows returning a call on an object type', () => {
2836
+ const spy = sinon.spy(logger_1.Logger.prototype, 'error');
2837
+ program.setFile('source/main.bs', `
2838
+ function abc(func as object) as dynamic
2839
+ return func()
2840
+ end function
2841
+ `);
2842
+ program.validate();
2843
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2844
+ (0, chai_1.expect)(spy.getCalls().map(x => { var _a, _b; return (_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toString(); }).filter(x => x === null || x === void 0 ? void 0 : x.includes('Error when calling plugin'))).to.eql([]);
2845
+ });
2846
+ it('allows calling func returned from other func', () => {
2847
+ const spy = sinon.spy(logger_1.Logger.prototype, 'error');
2848
+ program.setFile('source/calc.bs', `
2849
+ sub otherFuncFirst()
2850
+ ' forces getOperation to be referenceType called from ReferenceType
2851
+ end sub
2852
+
2853
+ function calc(a as dynamic, b as dynamic, op as string) as dynamic
2854
+ op = getOperation(op)
2855
+ return op(1, 2)
2856
+ end function
2857
+
2858
+ function getOperation(name as string) as object
2859
+ return {
2860
+ "sum": function(a as dynamic, b as dynamic) as dynamic
2861
+ return a + b
2862
+ end function
2863
+ }[name]
2864
+ end function
2865
+ `);
2866
+ program.validate();
2867
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2868
+ (0, chai_1.expect)(spy.getCalls().map(x => { var _a, _b; return (_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.toString(); }).filter(x => x === null || x === void 0 ? void 0 : x.includes('Error when calling plugin'))).to.eql([]);
2869
+ });
2870
+ it('allows returning something that matches a type statement type', () => {
2871
+ program.setFile('source/util.bs', `
2872
+ interface Person
2873
+ name as string
2874
+ age as integer
2875
+ end interface
2876
+
2877
+ type Wrapped = Person
2878
+
2879
+ function getWrapped() as Wrapped
2880
+ return {
2881
+ name: "Alice",
2882
+ age: 30
2883
+ }
2884
+ end function
2885
+ `);
2886
+ program.validate();
2887
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2888
+ });
2889
+ describe('inline interfaces', () => {
2890
+ it('allows returning an Associative Array that meets the interface', () => {
2891
+ program.setFile('source/main.bs', `
2892
+ function takesInline() as {id as string}
2893
+ return { id: "test" }
2894
+ end function
2895
+ `);
2896
+ program.validate();
2897
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2898
+ });
2899
+ it('allows returning a Node that meets the interface', () => {
2900
+ program.setFile('source/main.bs', `
2901
+ function takesInline() as {id as string}
2902
+ return createObject("roSGNode", "Poster")
2903
+ end function
2904
+ `);
2905
+ program.validate();
2906
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2907
+ });
2908
+ it('validates returning an AA that does not meet the interface', () => {
2909
+ program.setFile('source/main.bs', `
2910
+ function takesInline() as {id as integer}
2911
+ return {id: "hello"}
2912
+ end function
2913
+ `);
2914
+ program.validate();
2915
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2916
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('roAssociativeArray', '{id as integer}', {
2917
+ fieldMismatches: [{ name: 'id', expectedType: IntegerType_1.IntegerType.instance, actualType: StringType_1.StringType.instance }]
2918
+ }).message
2919
+ ]);
2920
+ });
2921
+ });
2922
+ it('allows returning invalid instead of typed array', () => {
2923
+ program.setFile('source/main.bs', `
2924
+ function getNumbers() as integer[]
2925
+ return invalid
2926
+ end function
2927
+ `);
2928
+ program.validate();
2929
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2930
+ });
2696
2931
  });
2697
2932
  describe('returnTypeCoercionMismatch', () => {
2698
2933
  it('allows functions, subs, and "function as void/dynamic" to not have return statements', () => {
@@ -3124,6 +3359,48 @@ describe('ScopeValidator', () => {
3124
3359
  ]);
3125
3360
  });
3126
3361
  });
3362
+ describe('inline interfaces', () => {
3363
+ it('allows assigning an Associative Array that meets the interface', () => {
3364
+ program.setFile('source/main.bs', `
3365
+ interface Iface
3366
+ inlineMember as {name as string}
3367
+ end interface
3368
+
3369
+ sub takesInline(someIface as Iface}
3370
+ someIface.inlineMember = {name: "test"}
3371
+ end sub
3372
+ `);
3373
+ program.validate();
3374
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3375
+ });
3376
+ it('validates assigning an AA that does not meet the interface', () => {
3377
+ program.setFile('source/main.bs', `
3378
+ interface Iface
3379
+ inlineMember as {name as string}
3380
+ end interface
3381
+
3382
+ sub takesInline(someIface as Iface}
3383
+ someIface.inlineMember = {name: 123}
3384
+ end sub
3385
+ `);
3386
+ program.validate();
3387
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
3388
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('roAssociativeArray', '{name as string}', {
3389
+ fieldMismatches: [{ name: 'name', expectedType: StringType_1.StringType.instance, actualType: IntegerType_1.IntegerType.instance }]
3390
+ }).message
3391
+ ]);
3392
+ });
3393
+ it('allows assigning invalid to typed arrays', () => {
3394
+ program.setFile('source/main.bs', `
3395
+ sub test()
3396
+ intArray as integer[] = invalid
3397
+ strArray as string[] = invalid
3398
+ end sub
3399
+ `);
3400
+ program.validate();
3401
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3402
+ });
3403
+ });
3127
3404
  });
3128
3405
  describe('operatorTypeMismatch', () => {
3129
3406
  it('finds when the type of the lhs is not compatible with the rhs type', () => {
@@ -3403,6 +3680,35 @@ describe('ScopeValidator', () => {
3403
3680
  program.validate();
3404
3681
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3405
3682
  });
3683
+ it('allows unions of compatible types', () => {
3684
+ program.setFile('source/main.bs', `
3685
+ function test(s as string or roString, i as integer or longinteger)
3686
+ s1 = s + "test"
3687
+ s2 = "test" + s
3688
+
3689
+ i1 = i + 5
3690
+ i2 = 5 + i
3691
+ end function
3692
+ `);
3693
+ program.validate();
3694
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3695
+ });
3696
+ it('allows type statement type of compatible types', () => {
3697
+ program.setFile('source/main.bs', `
3698
+ type number = integer or float
3699
+ type MyString = string or roString
3700
+
3701
+ function test(s as MyString, i as number)
3702
+ s1 = s + "test"
3703
+ s2 = "test" + s
3704
+
3705
+ i1 = i + 5
3706
+ i2 = 5 + i
3707
+ end function
3708
+ `);
3709
+ program.validate();
3710
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3711
+ });
3406
3712
  });
3407
3713
  describe('memberAccessibilityMismatch', () => {
3408
3714
  it('should flag when accessing a private member', () => {
@@ -3682,6 +3988,25 @@ describe('ScopeValidator', () => {
3682
3988
  ]);
3683
3989
  });
3684
3990
  });
3991
+ describe('circularReferenceDetected', () => {
3992
+ it('finds circular references in consts', () => {
3993
+ program.setFile('source/main.bs', `
3994
+ const A = B ' this is circular-reference
3995
+ const B = C ' this is circular-reference
3996
+ const C = A ' this is circular-reference
3997
+ sub main()
3998
+ print A ' this is circular-reference
3999
+ end sub
4000
+ `);
4001
+ program.validate();
4002
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
4003
+ DiagnosticMessages_1.DiagnosticMessages.circularReferenceDetected(['B', 'C', 'B']).message,
4004
+ DiagnosticMessages_1.DiagnosticMessages.circularReferenceDetected(['B', 'C', 'B']).message,
4005
+ DiagnosticMessages_1.DiagnosticMessages.circularReferenceDetected(['B', 'C', 'B']).message,
4006
+ DiagnosticMessages_1.DiagnosticMessages.circularReferenceDetected(['C', 'B', 'C']).message
4007
+ ]);
4008
+ });
4009
+ });
3685
4010
  describe('revalidation', () => {
3686
4011
  it('revalidates when a enum defined in a different namespace changes', () => {
3687
4012
  program.setFile('source/file1.bs', `
@@ -4106,6 +4431,44 @@ describe('ScopeValidator', () => {
4106
4431
  // there should be no more errors
4107
4432
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
4108
4433
  });
4434
+ it('recognizes when the type of a for-each loop variable changes', () => {
4435
+ program.setFile('source/file1.bs', `
4436
+ interface FooFace
4437
+ prop as string
4438
+ end interface
4439
+ `);
4440
+ program.setFile('source/file2.bs', `
4441
+ function loopFooFace(input as FooFace[])
4442
+ out = ""
4443
+ for each ff in input
4444
+ out += ff.prop
4445
+ end for
4446
+ return out
4447
+ end function
4448
+ `);
4449
+ program.validate();
4450
+ //currently no error
4451
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
4452
+ // change FooFace.prop to not work in other file
4453
+ program.setFile('source/file1.bs', `
4454
+ interface FooFace
4455
+ prop as integer
4456
+ end interface
4457
+ `);
4458
+ program.validate();
4459
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
4460
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+=', 'string', 'integer')
4461
+ ]);
4462
+ // change FooFace.prop to back to working
4463
+ program.setFile('source/file1.bs', `
4464
+ interface FooFace
4465
+ prop as string
4466
+ end interface
4467
+ `);
4468
+ program.validate();
4469
+ //currently no error
4470
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
4471
+ });
4109
4472
  });
4110
4473
  describe('preprocessor', () => {
4111
4474
  it('should process class inheritance correctly', () => {
@@ -4239,6 +4602,15 @@ describe('ScopeValidator', () => {
4239
4602
  DiagnosticMessages_1.DiagnosticMessages.notCallable('"string"').message
4240
4603
  ]);
4241
4604
  });
4605
+ it('allows calling an object type', () => {
4606
+ program.setFile('source/calc.bs', `
4607
+ function someFunc(otherFunc as object) as dynamic
4608
+ return otherFunc()
4609
+ end function
4610
+ `);
4611
+ program.validate();
4612
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
4613
+ });
4242
4614
  });
4243
4615
  describe('callFunc', () => {
4244
4616
  it('allows access to member of return type when return type is custom node', () => {