Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions src/Scope.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3807,6 +3807,25 @@ describe('Scope', () => {
expectTypeToBe(symbolTable.getSymbolType('key', opts), StringType);
});

it('should set the type of the for loop item whn the target is a union of typed arrays', () => {
let mainFile = program.setFile<BrsFile>('source/main.bs', `
sub process(data as integer[] or string[])
for each item in data
print item
end for
end sub
`);
program.validate();
expectZeroDiagnostics(program);
const forEachStmt = mainFile.ast.findChild<ForEachStatement>(isForEachStatement);
const symbolTable = forEachStmt.body.getSymbolTable();
const opts = { flags: SymbolTypeFlag.runtime };
const itemType = symbolTable.getSymbolType('item', opts) as UnionType;
expectTypeToBe(itemType, UnionType);
expect(itemType.types).to.include(IntegerType.instance);
expect(itemType.types).to.include(StringType.instance);
});

it('should use dynamic type for loop item when type cannot be inferred', () => {
let mainFile = program.setFile<BrsFile>('source/main.bs', `
sub process(data as roList)
Expand Down
3 changes: 3 additions & 0 deletions src/astUtils/reflection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,9 @@ export function isIterableType(value: any): boolean {
if (isArrayTypeLike(value) || isAssociativeArrayTypeLike(value)) {
return true;
}
if (isCompoundTypeOf(value, isIterableType)) {
return true;
}
if (isBuiltInType(value, 'roByteArray') || isBuiltInType(value, 'roList') || isBuiltInType(value, 'roXMLList') || isBuiltInType(value, 'roMessagePort')) {
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/bscPlugin/validation/BrsFileValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export class BrsFileValidator {
this.validateNoOptionalChainingInVarSet(node, [node.obj]);
},
ForEachStatement: (node) => {
//register the for loop variable
//registering the for loop variable happens in the visitor for Block, since the loop variable is scoped to the loop body
},
NamespaceStatement: (node) => {
if (!node?.nameExpression) {
Expand Down
54 changes: 54 additions & 0 deletions src/bscPlugin/validation/ScopeValidator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6651,5 +6651,59 @@ describe('ScopeValidator', () => {
DiagnosticMessages.notIterable('integer').message
]);
});

it('allows a union of iterable types to be iterated over', () => {
program.setFile('source/test.bs', `
sub doStuff(items as roList or roArray)
for each item in items
print item
end for
end sub
`);
program.validate();
expectZeroDiagnostics(program);
});

it('allows a union of typed arrays to be iterated over', () => {
program.setFile('source/test.bs', `
sub setAllText(text as string, labels as roSGNodeLabel[] or roSGNodeMultiStyleLabel[])
for each label in labels
label.text = text
end for
end sub
`);
program.validate();
expectZeroDiagnostics(program);
});

it('allows a type statement of a typed array to be iterated over', () => {
program.setFile('source/test.bs', `

type StringArray = string[]

sub printAllText(text as StringArray)
for each t in text
print t
end for
end sub
`);
program.validate();
expectZeroDiagnostics(program);
});

it('allows a type statement of a typed array to be iterated over', () => {
program.setFile('source/test.bs', `

type StringArray = string[]

sub printAllText(text as StringArray)
for each t in text
print t
end for
end sub
`);
program.validate();
expectZeroDiagnostics(program);
});
});
});
3 changes: 3 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2759,6 +2759,9 @@ export class Util {
return StringType.instance;
} else if (isBuiltInType(iteratorType, 'roByteArray')) {
return IntegerType.instance;
} else if (isUnionType(iteratorType)) {
const iteratorDefaultTypes = iteratorType.types.map(t => this.getIteratorDefaultType(t));
return getUniqueType(iteratorDefaultTypes, unionTypeFactory);
}
return DynamicType.instance;
}
Expand Down