diff --git a/src/Scope.spec.ts b/src/Scope.spec.ts index 0a64abd18..4800afd9c 100644 --- a/src/Scope.spec.ts +++ b/src/Scope.spec.ts @@ -25,6 +25,8 @@ import { UnionType } from './types/UnionType'; import { isFunctionStatement, isNamespaceStatement } from './astUtils/reflection'; import { ArrayType } from './types/ArrayType'; import { AssociativeArrayType } from './types/AssociativeArrayType'; +import { InterfaceType } from '.'; +import { ComponentType } from './types/ComponentType'; describe('Scope', () => { let sinon = sinonImport.createSandbox(); @@ -2940,6 +2942,66 @@ describe('Scope', () => { expect((unionDefaultType as UnionType).types).to.include(StringType.instance); expect((unionDefaultType as UnionType).types).to.include(IntegerType.instance); }); + + it('should allow built in component types', () => { + let utilFile = program.setFile('source/util.bs', ` + sub process(data as roAssociativeArray[]) + for each datum in data + print datum + end for + end sub + `); + program.validate(); + expectZeroDiagnostics(program); + const processFnScope = utilFile.getFunctionScopeAtPosition(util.createPosition(2, 24)); + const symbolTable = processFnScope.symbolTable; + const opts = { flags: SymbolTypeFlag.runtime }; + expectTypeToBe(symbolTable.getSymbolType('data', opts), ArrayType); + expectTypeToBe(symbolTable.getSymbolType('datum', opts), InterfaceType); + }); + + it('should allow class types', () => { + let utilFile = program.setFile('source/util.bs', ` + sub process(data as Klass[]) + for each datum in data + print datum.name + end for + end sub + + + class Klass + name as string + end class + `); + program.validate(); + expectZeroDiagnostics(program); + const processFnScope = utilFile.getFunctionScopeAtPosition(util.createPosition(2, 24)); + const symbolTable = processFnScope.symbolTable; + const opts = { flags: SymbolTypeFlag.runtime }; + const dataType = symbolTable.getSymbolType('data', opts); + expectTypeToBe(dataType, ArrayType); + expectTypeToBe((dataType as ArrayType).defaultType, ClassType); + expect((dataType as ArrayType).defaultType.toString()).to.equal('Klass'); + }); + + it('should allow component types', () => { + let utilFile = program.setFile('source/util.bs', ` + sub process(labels as roSgNodeLabel[]) + for each label in labels + print label.text + end for + end sub + `); + program.validate(); + expectZeroDiagnostics(program); + const processFnScope = utilFile.getFunctionScopeAtPosition(util.createPosition(2, 24)); + const symbolTable = processFnScope.symbolTable; + const opts = { flags: SymbolTypeFlag.runtime }; + const dataType = symbolTable.getSymbolType('labels', opts); + expectTypeToBe(dataType, ArrayType); + expectTypeToBe((dataType as ArrayType).defaultType, ComponentType); + expect((dataType as ArrayType).defaultType.toString()).to.equal('roSGNodeLabel'); + }); }); describe('callFunc invocations', () => { diff --git a/src/astUtils/reflection.ts b/src/astUtils/reflection.ts index ceab34e2f..67d232835 100644 --- a/src/astUtils/reflection.ts +++ b/src/astUtils/reflection.ts @@ -1,5 +1,5 @@ import type { Body, AssignmentStatement, Block, ExpressionStatement, CommentStatement, ExitForStatement, ExitWhileStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, InterfaceFieldStatement, InterfaceMethodStatement, InterfaceStatement, EnumStatement, EnumMemberStatement, TryCatchStatement, CatchStatement, ThrowStatement, MethodStatement, FieldStatement, ConstStatement, ContinueStatement } from '../parser/Statement'; -import type { LiteralExpression, BinaryExpression, CallExpression, FunctionExpression, DottedGetExpression, XmlAttributeGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, TemplateStringExpression, TaggedTemplateStringExpression, AnnotationExpression, FunctionParameterExpression, AAMemberExpression, TypeExpression, TypeCastExpression } from '../parser/Expression'; +import type { LiteralExpression, BinaryExpression, CallExpression, FunctionExpression, DottedGetExpression, XmlAttributeGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, TemplateStringExpression, TaggedTemplateStringExpression, AnnotationExpression, FunctionParameterExpression, AAMemberExpression, TypeExpression, TypeCastExpression, TypedArrayExpression } from '../parser/Expression'; import type { BrsFile } from '../files/BrsFile'; import type { XmlFile } from '../files/XmlFile'; import type { BscFile, File, TypedefProvider } from '../interfaces'; @@ -262,6 +262,9 @@ export function isTypeExpression(element: any): element is TypeExpression { export function isTypeCastExpression(element: any): element is TypeCastExpression { return element?.kind === AstNodeKind.TypeCastExpression; } +export function isTypedArrayExpression(element: any): element is TypedArrayExpression { + return element?.kind === AstNodeKind.TypedArrayExpression; +} // BscType reflection export function isStringType(value: any): value is StringType { diff --git a/src/bscPlugin/validation/ScopeValidator.ts b/src/bscPlugin/validation/ScopeValidator.ts index b1f75983b..831a79b46 100644 --- a/src/bscPlugin/validation/ScopeValidator.ts +++ b/src/bscPlugin/validation/ScopeValidator.ts @@ -1,5 +1,5 @@ import { URI } from 'vscode-uri'; -import { isAssignmentStatement, isBinaryExpression, isBrsFile, isClassType, isDynamicType, isEnumMemberType, isEnumType, isFunctionExpression, isLiteralExpression, isNamespaceStatement, isObjectType, isPrimitiveType, isTypeExpression, isTypedFunctionType, isUnionType, isVariableExpression, isXmlScope } from '../../astUtils/reflection'; +import { isAssignmentStatement, isBinaryExpression, isBrsFile, isClassType, isDynamicType, isEnumMemberType, isEnumType, isFunctionExpression, isLiteralExpression, isNamespaceStatement, isObjectType, isPrimitiveType, isTypeExpression, isTypedArrayExpression, isTypedFunctionType, isUnionType, isVariableExpression, isXmlScope } from '../../astUtils/reflection'; import { Cache } from '../../Cache'; import { DiagnosticMessages } from '../../DiagnosticMessages'; import type { BrsFile } from '../../files/BrsFile'; @@ -80,9 +80,11 @@ export class ScopeValidator { private checkIfUsedAsTypeExpression(expression: AstNode): boolean { - //TODO: this is much faster than node.findAncestor(), but will not work for "complicated" type expressions like UnionTypes + //TODO: this is much faster than node.findAncestor(), but may need to be updated for "complicated" type expressions if (isTypeExpression(expression) || - isTypeExpression(expression.parent)) { + isTypeExpression(expression.parent) || + isTypedArrayExpression(expression) || + isTypedArrayExpression(expression.parent)) { return true; } if (isBinaryExpression(expression.parent)) { @@ -90,7 +92,7 @@ export class ScopeValidator { while (isBinaryExpression(currentExpr) && currentExpr.operator.kind === TokenKind.Or) { currentExpr = currentExpr.parent; } - return isTypeExpression(currentExpr); + return isTypeExpression(currentExpr) || isTypedArrayExpression(currentExpr); } return false; } diff --git a/src/parser/AstNode.ts b/src/parser/AstNode.ts index aa417cf59..51e9c1b1f 100644 --- a/src/parser/AstNode.ts +++ b/src/parser/AstNode.ts @@ -237,5 +237,5 @@ export enum AstNodeKind { Block = 'Block', TypeExpression = 'TypeExpression', TypeCastExpression = 'TypeCastExpression', - ArrayTypeExpression = 'ArrayTypeExpression' + TypedArrayExpression = 'TypedArrayExpression' } diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index 2cde0999a..2be701344 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -1819,7 +1819,7 @@ export class TypedArrayExpression extends Expression { ); } - public readonly kind = AstNodeKind.ArrayTypeExpression; + public readonly kind = AstNodeKind.TypedArrayExpression; public range: Range;