diff --git a/src/bscPlugin/validation/ScopeValidator.spec.ts b/src/bscPlugin/validation/ScopeValidator.spec.ts index 67ad1e97a..16d3c9d29 100644 --- a/src/bscPlugin/validation/ScopeValidator.spec.ts +++ b/src/bscPlugin/validation/ScopeValidator.spec.ts @@ -128,6 +128,105 @@ describe('ScopeValidator', () => { }); describe('argumentTypeMismatch', () => { + it('param `as object` supports all known types', () => { + program.setFile('source/file.bs', ` + sub main() + consoleLog(Direction.up) + consoleLog(true) + consoleLog(main) + consoleLog(1.2) + consoleLog({} as Video) + end sub + + sub consoleLog(thing as object) + print thing + end sub + + interface Video + url as string + end interface + enum Direction + up = "up" + down = "down" + end enum + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('`as object` var can be passed to various param types', () => { + program.setFile('source/file.bs', ` + sub main() + obj = {} as object + + printBoolean(obj) + printClass(obj) + printDouble(obj) + printEnum(obj) + printFloat(obj) + printFunction(obj) + printInteger(obj) + printInterface(obj) + printLongInteger(obj) + printString(obj) + end sub + + sub printBoolean(value as boolean) + print value + end sub + + class Person + name as string + end class + + sub printClass(value as Person) + print value + end sub + + sub printDouble(value as double) + print value + end sub + + enum Direction + up = "up" + end enum + + sub printEnum(value as Direction) + print value + end sub + + sub printFloat(value as float) + print value + end sub + + sub printFunction(value as function) + print value + end sub + + interface Video + url as string + end interface + + sub printInterface(value as Video) + print value + end sub + + sub printInteger(value as integer) + print value + end sub + + sub printLongInteger(value as LongInteger) + print value + end sub + + sub printString(value as string) + print value + end sub + `); + program.validate(); + expectZeroDiagnostics(program); + }); + it('treats string enums as strings when assigned to string vars', () => { program.setFile('source/file.bs', ` diff --git a/src/types/BooleanType.ts b/src/types/BooleanType.ts index ab41e2a64..46093c9c2 100644 --- a/src/types/BooleanType.ts +++ b/src/types/BooleanType.ts @@ -1,4 +1,4 @@ -import { isBooleanType, isDynamicType } from '../astUtils/reflection'; +import { isBooleanType, isDynamicType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -16,7 +16,8 @@ export class BooleanType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isBooleanType(targetType) || - isDynamicType(targetType) + isDynamicType(targetType) || + isObjectType(targetType) ); } diff --git a/src/types/ClassType.ts b/src/types/ClassType.ts index 5e7dd5f1e..9403730d6 100644 --- a/src/types/ClassType.ts +++ b/src/types/ClassType.ts @@ -1,4 +1,4 @@ -import { isClassType, isDynamicType } from '../astUtils/reflection'; +import { isClassType, isDynamicType, isObjectType } from '../astUtils/reflection'; import type { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; import { InheritableType } from './InheritableType'; @@ -14,7 +14,7 @@ export class ClassType extends InheritableType { public isTypeCompatible(targetType: BscType) { if (this.isEqual(targetType)) { return true; - } else if (isDynamicType(targetType)) { + } else if (isDynamicType(targetType) || isObjectType(targetType)) { return true; } else if (isClassType(targetType)) { return this.isTypeDescendent(targetType); diff --git a/src/types/DoubleType.ts b/src/types/DoubleType.ts index 2feac600c..389a49d64 100644 --- a/src/types/DoubleType.ts +++ b/src/types/DoubleType.ts @@ -1,4 +1,4 @@ -import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType } from '../astUtils/reflection'; +import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -17,6 +17,7 @@ export class DoubleType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isDynamicType(targetType) || + isObjectType(targetType) || isIntegerType(targetType) || isFloatType(targetType) || isDoubleType(targetType) || diff --git a/src/types/EnumType.ts b/src/types/EnumType.ts index 2f8657180..2cf4d46a8 100644 --- a/src/types/EnumType.ts +++ b/src/types/EnumType.ts @@ -1,4 +1,4 @@ -import { isDynamicType, isEnumMemberType, isEnumType } from '../astUtils/reflection'; +import { isDynamicType, isEnumMemberType, isEnumType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; import { DynamicType } from './DynamicType'; @@ -19,6 +19,7 @@ export class EnumType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isDynamicType(targetType) || + isObjectType(targetType) || this.isEqual(targetType) || (isEnumMemberType(targetType) && targetType?.enumName.toLowerCase() === this.name.toLowerCase()) ); diff --git a/src/types/FloatType.ts b/src/types/FloatType.ts index d4825a8eb..a091b3e3f 100644 --- a/src/types/FloatType.ts +++ b/src/types/FloatType.ts @@ -1,4 +1,4 @@ -import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType } from '../astUtils/reflection'; +import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -16,6 +16,7 @@ export class FloatType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isDynamicType(targetType) || + isObjectType(targetType) || isIntegerType(targetType) || isFloatType(targetType) || isDoubleType(targetType) || diff --git a/src/types/FunctionType.ts b/src/types/FunctionType.ts index 137410bdd..871a47e35 100644 --- a/src/types/FunctionType.ts +++ b/src/types/FunctionType.ts @@ -1,4 +1,4 @@ -import { isFunctionType } from '../astUtils/reflection'; +import { isDynamicType, isFunctionType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; import { DynamicType } from './DynamicType'; @@ -39,7 +39,10 @@ export class FunctionType extends BscType { } public isTypeCompatible(targetType: BscType) { - if (targetType instanceof DynamicType) { + if ( + isDynamicType(targetType) || + isObjectType(targetType) + ) { return true; } return this.isEqual(targetType); diff --git a/src/types/IntegerType.ts b/src/types/IntegerType.ts index b03b33c53..b72dca2d6 100644 --- a/src/types/IntegerType.ts +++ b/src/types/IntegerType.ts @@ -1,4 +1,4 @@ -import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType } from '../astUtils/reflection'; +import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -16,6 +16,7 @@ export class IntegerType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isDynamicType(targetType) || + isObjectType(targetType) || isIntegerType(targetType) || isFloatType(targetType) || isDoubleType(targetType) || diff --git a/src/types/InterfaceType.ts b/src/types/InterfaceType.ts index 07d57ccc7..057d3baa3 100644 --- a/src/types/InterfaceType.ts +++ b/src/types/InterfaceType.ts @@ -1,5 +1,5 @@ import { SymbolTypeFlag } from '../SymbolTable'; -import { isDynamicType, isInterfaceType, isUnionType, isInheritableType } from '../astUtils/reflection'; +import { isDynamicType, isInterfaceType, isUnionType, isInheritableType, isObjectType } from '../astUtils/reflection'; import type { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; import { InheritableType } from './InheritableType'; @@ -15,11 +15,11 @@ export class InterfaceType extends InheritableType { public readonly kind = BscTypeKind.InterfaceType; public isTypeCompatible(targetType: BscType) { - //TODO: We need to make sure that things don't get assigned to built-in types - if (this.isEqual(targetType)) { + if (isDynamicType(targetType) || isObjectType(targetType)) { return true; } - if (isDynamicType(targetType)) { + //TODO: We need to make sure that things don't get assigned to built-in types + if (this.isEqual(targetType)) { return true; } const ancestorTypes = this.getAncestorTypeList(); diff --git a/src/types/InvalidType.ts b/src/types/InvalidType.ts index 57e5ca20f..239bc5139 100644 --- a/src/types/InvalidType.ts +++ b/src/types/InvalidType.ts @@ -1,4 +1,4 @@ -import { isDynamicType, isInvalidType } from '../astUtils/reflection'; +import { isDynamicType, isInvalidType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -16,7 +16,8 @@ export class InvalidType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isInvalidType(targetType) || - isDynamicType(targetType) + isDynamicType(targetType) || + isObjectType(targetType) ); } diff --git a/src/types/LongIntegerType.ts b/src/types/LongIntegerType.ts index 1ce0ae331..58b55f7d7 100644 --- a/src/types/LongIntegerType.ts +++ b/src/types/LongIntegerType.ts @@ -1,4 +1,4 @@ -import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType } from '../astUtils/reflection'; +import { isDoubleType, isDynamicType, isFloatType, isIntegerType, isLongIntegerType, isObjectType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -16,6 +16,7 @@ export class LongIntegerType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isDynamicType(targetType) || + isObjectType(targetType) || isIntegerType(targetType) || isFloatType(targetType) || isDoubleType(targetType) || diff --git a/src/types/StringType.ts b/src/types/StringType.ts index 1b6f843b3..0a5505243 100644 --- a/src/types/StringType.ts +++ b/src/types/StringType.ts @@ -1,4 +1,4 @@ -import { isDynamicType, isEnumMemberType, isEnumType, isStringType } from '../astUtils/reflection'; +import { isDynamicType, isEnumMemberType, isEnumType, isObjectType, isStringType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -20,6 +20,7 @@ export class StringType extends BscType { return ( isStringType(targetType) || isDynamicType(targetType) || + isObjectType(targetType) || //string enums are compatible with strings ( (isEnumType(targetType) || isEnumMemberType(targetType)) && isStringType(targetType.underlyingType) diff --git a/src/types/UnionType.ts b/src/types/UnionType.ts index fbc8848f2..fe6bd5ce0 100644 --- a/src/types/UnionType.ts +++ b/src/types/UnionType.ts @@ -1,5 +1,5 @@ import type { GetTypeOptions } from '../interfaces'; -import { isDynamicType, isUnionType } from '../astUtils/reflection'; +import { isDynamicType, isObjectType, isUnionType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { ReferenceType } from './ReferenceType'; import { findTypeUnion, getUniqueType } from './helpers'; @@ -55,7 +55,7 @@ export class UnionType extends BscType { } isTypeCompatible(targetType: BscType): boolean { - if (isDynamicType(targetType)) { + if (isDynamicType(targetType) || isObjectType(targetType)) { return true; } if (isUnionType(targetType)) { diff --git a/src/types/VoidType.ts b/src/types/VoidType.ts index 11aa50b50..17930b54b 100644 --- a/src/types/VoidType.ts +++ b/src/types/VoidType.ts @@ -1,4 +1,4 @@ -import { isDynamicType, isVoidType } from '../astUtils/reflection'; +import { isDynamicType, isObjectType, isVoidType } from '../astUtils/reflection'; import { BscType } from './BscType'; import { BscTypeKind } from './BscTypeKind'; @@ -16,7 +16,8 @@ export class VoidType extends BscType { public isTypeCompatible(targetType: BscType) { return ( isVoidType(targetType) || - isDynamicType(targetType) + isDynamicType(targetType) || + isObjectType(targetType) ); }