mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-22 17:39:19 +00:00
* initial working language server * first hacky version of source parsing and type checking * first iteration of method body parser * add support for prefix/postfix inc expressions * add basic support for parsing new expressions * different attempt to parse using collapsable text ranges * fix parsing of binary operstors following a bracket expression * updated validation to use new JavaTypes module instead of MTIs * add support for array-literal expressions * fix || and && not being tokenized as operators allow float literals starting with dot * add new method body parser to use direct linear parsing * add super as an object literal * fix interface constructors check constructor type modifiers * fix assignment operator types * Fix resolving of enclosed type identifiers * add default constructor for class types with no explicit constructors * add missing constructor validator * add constructor parameters to list of resolvable types * update SourceMethod to pass name in super constructor * add Any* classes to reduce cascading errors * update method call parameter checking use isTypeAssignable instead of getParameterCompatibleTypeSignatures * tidy up isTypeAssignable allow class equivilents for primitives * add more info when methods/ctrs cannot be matched * allow interfaces to be cast to class instances * use isTypeAssignable for checking branch test expressions * allow AnyValue to be a constant value * split shift operators from bitwise operators * add support for literal numbers to be assignable to multiple primtive types * clear diagnostics when document is closed * update check for cast expression * casting only applies to qualified term not a whole expression * allow all primitive-number-type casts * add support for synchronized statement * update primitive type compatibility * allow null to be cast to any non-primitve * use better regex for string literals * allow character literals to be assigned to number types * add support for array qualifiers after a variable name * make sure any long specifier is stripped from a bigint value * improve invalid array expression message add AnyType array element to prevent cascading errors * make default a modifer keyword for interface default method support * initial support for wildcard type arguments * fix parse issue with nested generic types * allow generic types to be assigned to inherited types with compatible type arguments * allow unicode characters, $ and _ in identifiers * map primitive types to their boxed versions for class member * support assert statement * allow unicode char literals * make type parser and body parser use same tokenizer * reuse parsed tokens instead of tokenizing each method body * re-add throws as a keyword * treat default and synchronized as modifiers * add SourceInitialiser support * refactor to prepare for merging with type parsing * add support for array qualifiers in type identifiers * pass scoped type instead of method to typeIdent * update ResolvableType to use same type resolving as method body parsing * add support for post-name array qualifiers in fields and parameters * post-name array qualifiers in method decls * add type variables to SourceMethod * initial attempt to support type variable arguments in methods * specialise methods with type variables * don't require default interface methods to be implemented * make variable arity parameters an array type * tidy array constructors and fix some warnings * update isCallCompatible to handle variable arity calls * improve assert statement support * parse labels and break/continue targets * refactor new term qualifiers * add support for generic inferred-type arguments * improve modifier checks for interface types * improve reporting of unresolved type errors * fix type checking of field and method declarations * add missng strictfp modifier * refactor in preparation for parsing local types * replace Locals with scopeable MethodDeclarations to allow labels and types to be stored * initial changes to support local type declarations * update to use new set of SourceX classes * refactor to allow expressions to have a type scope * replace regex parsing with linear parsing * generate source types before parsing * fix support for resolving type variables in method declarations * fix checking of array literal compatability * report errors from unit parsing * remove local modifier validation during parse add parameter modifier checking to validation * allow trailing comma for array literals * start separating validation from parsing * add support for parsing enum values * allow uppercase 0X in hex literals * include enclosing types in identifier search * add support for parsing parameterless lambdas * ignore unresolved types in extends/implements * implement specialisation of SourceType * allow super as a member qualifier * allow empty enums * don't report missing constructors if superclass has none * update typemap declarations to use CEIType instead of JavaType * fix resolving of class type variables * fix bad imports when resolving annotations * allow null scope in findIdentifier * add support for static member imports * import types from same package * remove this qualifier from isCastExpression * add hex exponent support * parse try-with-resources * fix resolving imported enclosed types * extract expression types into separate files * extract statement types into separate files * fix type warnings * extract literals into separate files * remove Value class, add NewExpression and separate out Any classes * rename source types module * remove some parse checks that should be in verify * support token extraction in expressions * implement resolveExpression * add type cast checking * check for valid type in class member expressions * allow assigns for assignable type arguments * improve reporting of unresolved identifiers * add new array validation * validate array literals * validate array indexes * improve validation of binary operators * rename ResolvedType to ResolvedValue * improve checking of number literals * support package name as a resolved value * implement method body and ststement validation * improve method call resolving * add support for this() and super() constructor calls * remove return type for source constructors * add checks for unary operators * ensure tokens are assigned for qualified expressions * check castability using type assignments * add implicit enum methods values() and valueOf() * add basic type checking of lambda expressions * fix return type check * fix assert statement checks * improve support for ternary operators in assignments and method invocations * perform more detailed search of implemented methods * initial test of context-dependant code completion * support package, type and static field import completion * support for member expressions * use exact type signatures for locating types for completion items * add support for field and method docs * add support for docs in source types * support member completion for array types improve comment formatting * ensure Object is always last in the list of inherited types * add owning method to statements create common keyword statement class * improve code completion list add method parameters order list items by scope * add source types to list hide this and super for non-methods * fix bad member resolution at end of block fix missing method and type docs * add support for editing multiple files * allow multiple source files to be used in parsing * load and parse files at startup * add support for displaying method signatures * add single trace function with timestamps * implement shceduleReparse to reduce parsing load while typing * remove parsed type list logging * wait for reparsing before returning method signatures * resolve new object contructors * improve extraction of parameter docs * update @types/vscode * cache decoded android library in globalStoragePath * load single android library cache from local folder * android-29 library cache * allow configurable app root setting * set configurable trace logging and update section names * description updates * handle null token passed to ParseProblem * refactoring * Rename language client extension to Android * ignore unnamed type declarations * handle java file change notifications * make sure we only try and parse java files * add option to allow language server to be shutdown * simplify handling of this and class member qualifiers * relocate java-mti package into project * get main node install to install langserver dependencies * remove debugging pause * rename body-parser3 to body-parser * clean up import resolving code * remove unused field from ResolvedImport * remove validation modules that used old parser types * remove old parser files * remove redundant types and functions used by old parser * move addproblem into TokenList * remove unused ResolvedType class * validate more statements * add support for parsing and validating anonymous types * hide some method modifiers which aren't useful to show * code comments and minor improvements * fix some type warnings * improve support for completion of enum values * add type name to parameter completion labels * ignore synthetic members in completion list * use a specialised map for handling case-insenstive file uris * add basic build script * reference java-mti package from GitHub * revert @types/vscode * update initial file loading to use URIs passed from the client changes to the appSourceRoot now require an extension restart * add support for loading filtered androidx libraries for code completion * update version of java-mti * add mixpanel package * add basic analytics * fix dependency versions * fix dependency versions * set empty cache file markers * add language server debug config * add file to build script * add unqualified type members when inside a method * apply statics filter to enum values * add basic debugger analytics * include current time in startup event * add terminate reason to debugger * update changelog and readme
394 lines
15 KiB
JavaScript
394 lines
15 KiB
JavaScript
/**
|
|
* @typedef {import('./tokenizer').Token} Token
|
|
* @typedef {import('./anys').ResolvedValue} ResolvedValue
|
|
* @typedef {import('./body-types').ResolvedIdent} ResolvedIdent
|
|
*/
|
|
const ParseProblem = require('./parsetypes/parse-problem');
|
|
const { TypeVariable, JavaType, PrimitiveType, NullType, ArrayType, CEIType, WildcardType, TypeVariableType, InferredTypeArgument } = require('java-mti');
|
|
const { AnyType, ArrayValueType, LambdaType, MultiValueType } = require('./anys');
|
|
const { ResolveInfo } = require('./body-types');
|
|
const { NumberLiteral } = require('./expressiontypes/literals/Number');
|
|
|
|
/**
|
|
* @param {ResolveInfo} ri
|
|
* @param {ResolvedIdent} expression
|
|
* @param {JavaType} assign_type
|
|
*/
|
|
function checkAssignment(ri, assign_type, expression) {
|
|
const value = expression.resolveExpression(ri);
|
|
checkTypeAssignable(assign_type, value, () => expression.tokens, ri.problems);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {JavaType} variable_type
|
|
* @param {ResolvedValue} value
|
|
* @param {() => Token|Token[]} tokens
|
|
* @param {ParseProblem[]} problems
|
|
*/
|
|
function checkTypeAssignable(variable_type, value, tokens, problems) {
|
|
if (value instanceof NumberLiteral) {
|
|
if (!value.isCompatibleWith(variable_type)) {
|
|
incompatibleTypesError(variable_type, value.type, () => value.tokens(), problems);
|
|
}
|
|
return;
|
|
}
|
|
if (value instanceof MultiValueType) {
|
|
value.types.forEach(t => checkTypeAssignable(variable_type, t, tokens, problems));
|
|
return;
|
|
}
|
|
if (value instanceof ArrayValueType) {
|
|
checkArrayLiteral(variable_type, value, tokens, problems);
|
|
return;
|
|
}
|
|
if (value instanceof LambdaType) {
|
|
checkLambdaAssignable(variable_type, value, tokens, problems);
|
|
return;
|
|
}
|
|
if (value instanceof JavaType) {
|
|
if (!isTypeAssignable(variable_type, value)) {
|
|
incompatibleTypesError(variable_type, value, tokens, problems);
|
|
}
|
|
return;
|
|
}
|
|
problems.push(ParseProblem.Error(tokens(), `Field, variable or method call expected`));
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {JavaType} variable_type
|
|
* @param {JavaType} value_type
|
|
* @param {() => Token|Token[]} tokens
|
|
* @param {ParseProblem[]} problems
|
|
*/
|
|
function incompatibleTypesError(variable_type, value_type, tokens, problems) {
|
|
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Expression of type '${value_type.fullyDottedTypeName}' cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {JavaType} variable_type
|
|
* @param {LambdaType} value
|
|
* @param {() => Token|Token[]} tokens
|
|
* @param {ParseProblem[]} problems
|
|
*/
|
|
function checkLambdaAssignable(variable_type, value, tokens, problems) {
|
|
const res = isLambdaAssignable(variable_type, value);
|
|
if (res === true) {
|
|
return;
|
|
}
|
|
switch (res[0]) {
|
|
case 'non-interface':
|
|
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Cannot assign lambda expression to type '${variable_type.fullyDottedTypeName}'`));
|
|
return;
|
|
case 'no-methods':
|
|
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Interface '${variable_type.fullyDottedTypeName}' contains no abstract methods compatible with the specified lambda expression`));
|
|
return;
|
|
case 'param-count':
|
|
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Interface method '${variable_type.methods[0].label}' and lambda expression have different parameter counts`));
|
|
return;
|
|
case 'bad-param':
|
|
problems.push(ParseProblem.Error(tokens(), `Incompatible types: Interface method '${variable_type.methods[0].label}' and lambda expression have different parameter types`));
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {JavaType} variable_type
|
|
* @param {LambdaType} value
|
|
*/
|
|
function isLambdaAssignable(variable_type, value) {
|
|
if (!(variable_type instanceof CEIType) || variable_type.typeKind !== 'interface') {
|
|
return ['non-interface'];
|
|
}
|
|
// the functional interface must only contain one abstract method excluding public Object methods
|
|
// and ignoring type-compatible methods from superinterfaces.
|
|
// this is quite complicated to calculate, so for now, just check against the most common case: a simple interface type with
|
|
// a single abstract method
|
|
if (variable_type.supers.length > 1) {
|
|
return true;
|
|
}
|
|
if (variable_type.methods.length === 0) {
|
|
return ['no-methods']
|
|
}
|
|
if (variable_type.methods.length > 1) {
|
|
return true;
|
|
}
|
|
const intf_method = variable_type.methods[0];
|
|
const intf_params = intf_method.parameters;
|
|
if (intf_params.length !== value.param_types.length) {
|
|
return ['param-count'];
|
|
}
|
|
|
|
for (let i = 0; i < intf_params.length; i++) {
|
|
// explicit parameter types must match exactly
|
|
if (value.param_types[i] instanceof AnyType) {
|
|
continue;
|
|
}
|
|
if (intf_params[i].type instanceof AnyType) {
|
|
continue;
|
|
}
|
|
if (intf_params[i].type.typeSignature !== value.param_types[i].typeSignature) {
|
|
return ['bad-param']
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {JavaType} variable_type
|
|
* @param {ArrayValueType} value_type
|
|
* @param {() => Token|Token[]} tokens
|
|
* @param {ParseProblem[]} problems
|
|
*/
|
|
function checkArrayLiteral(variable_type, value_type, tokens, problems) {
|
|
if (!(variable_type instanceof ArrayType)) {
|
|
problems.push(ParseProblem.Error(tokens(), `Array expression cannot be assigned to a variable of type '${variable_type.fullyDottedTypeName}'`));
|
|
return;
|
|
}
|
|
if (value_type.elements.length === 0) {
|
|
// empty arrays are compatible with all array types
|
|
return;
|
|
}
|
|
const element_type = variable_type.elementType;
|
|
value_type.elements.forEach(element => {
|
|
checkArrayElement(element_type, element.value, element.tokens);
|
|
});
|
|
|
|
/**
|
|
* @param {JavaType} element_type
|
|
* @param {ResolvedValue} value_type
|
|
* @param {Token[]} tokens
|
|
*/
|
|
function checkArrayElement(element_type, value_type, tokens) {
|
|
if (value_type instanceof NumberLiteral) {
|
|
if (!value_type.isCompatibleWith(element_type)) {
|
|
incompatibleTypesError(element_type, value_type.type, () => tokens, problems);
|
|
}
|
|
return;
|
|
}
|
|
if (value_type instanceof JavaType) {
|
|
if (!isTypeAssignable(element_type, value_type)) {
|
|
incompatibleTypesError(element_type, value_type, () => tokens, problems);
|
|
}
|
|
return;
|
|
}
|
|
if (value_type instanceof ArrayValueType) {
|
|
checkArrayLiteral(element_type, value_type, () => tokens, problems);
|
|
return;
|
|
}
|
|
problems.push(ParseProblem.Error(tokens, `Expression expected`));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {ResolveInfo} ri
|
|
* @param {ResolvedIdent} d
|
|
* @param {'index'|'dimension'} kind
|
|
*/
|
|
function checkArrayIndex(ri, d, kind) {
|
|
const idx = d.resolveExpression(ri);
|
|
if (idx instanceof NumberLiteral) {
|
|
if (!idx.isCompatibleWith(PrimitiveType.map.I)) {
|
|
ri.problems.push(ParseProblem.Error(d.tokens, `Value '${idx.toNumber()}' is not valid as an array ${kind}`));
|
|
}
|
|
else if (idx.toNumber() < 0) {
|
|
ri.problems.push(ParseProblem.Error(d.tokens, `Negative array ${kind}: ${idx.toNumber()}`));
|
|
}
|
|
return;
|
|
}
|
|
if (idx instanceof PrimitiveType) {
|
|
if (!/^[BSI]$/.test(idx.typeSignature)) {
|
|
ri.problems.push(ParseProblem.Error(d.tokens, `Expression of type '${idx.label}' is not valid as an array ${kind}`));
|
|
}
|
|
return;
|
|
}
|
|
ri.problems.push(ParseProblem.Error(d.tokens, `Integer value expected`));
|
|
}
|
|
|
|
/**
|
|
* Set of regexes to map source primitives to their destination types.
|
|
* eg, long (J) is type-assignable to long, float and double (and their boxed counterparts)
|
|
* Note that void (V) is never type-assignable to anything
|
|
*/
|
|
const valid_primitive_types = {
|
|
// conversions from a primitive to a value
|
|
from: {
|
|
B: /^[BSIJFD]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Float|Double);$/,
|
|
S: /^[SIJFD]$|^Ljava\/lang\/(Short|Integer|Long|Float|Double);$/,
|
|
I: /^[IJFD]$|^Ljava\/lang\/(Integer|Long|Float|Double);$/,
|
|
J: /^[JFD]$|^Ljava\/lang\/(Long|Float|Double);$/,
|
|
F: /^[FD]$|^Ljava\/lang\/(Float|Double);$/,
|
|
D: /^D$|^Ljava\/lang\/(Double);$/,
|
|
C: /^[CIJFD]$|^Ljava\/lang\/(Character|Integer|Long|Float|Double);$/,
|
|
Z: /^Z$|^Ljava\/lang\/(Boolean);$/,
|
|
V: /$^/, // V.test() always returns false
|
|
},
|
|
// conversions to a primitive from a value
|
|
to: {
|
|
B: /^[B]$|^Ljava\/lang\/(Byte);$/,
|
|
S: /^[BS]$|^Ljava\/lang\/(Byte|Short);$/,
|
|
I: /^[BSIC]$|^Ljava\/lang\/(Byte|Short|Integer|Character);$/,
|
|
J: /^[BSIJC]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Character);$/,
|
|
F: /^[BSIJCF]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Character|Float);$/,
|
|
D: /^[BSIJCFD]$|^Ljava\/lang\/(Byte|Short|Integer|Long|Character|Float|Double);$/,
|
|
C: /^C$|^Ljava\/lang\/(Character);$/,
|
|
Z: /^Z$|^Ljava\/lang\/(Boolean);$/,
|
|
V: /$^/, // V.test() always returns false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if a value of value_type is assignable to a variable of dest_type
|
|
* @param {JavaType} dest_type
|
|
* @param {JavaType|NumberLiteral|LambdaType|MultiValueType} value_type
|
|
*/
|
|
function isTypeAssignable(dest_type, value_type) {
|
|
|
|
if (value_type instanceof NumberLiteral) {
|
|
return value_type.isCompatibleWith(dest_type);
|
|
}
|
|
|
|
if (value_type instanceof LambdaType) {
|
|
return isLambdaAssignable(dest_type, value_type) === true;
|
|
}
|
|
|
|
if (value_type instanceof MultiValueType) {
|
|
return value_type.types.every(t => {
|
|
if (t instanceof JavaType || t instanceof NumberLiteral || t instanceof LambdaType || t instanceof MultiValueType)
|
|
return isTypeAssignable(dest_type, t);
|
|
return false;
|
|
});
|
|
}
|
|
|
|
let is_assignable = false;
|
|
if (dest_type.typeSignature === value_type.typeSignature) {
|
|
// exact signature match
|
|
is_assignable = true;
|
|
} else if (dest_type instanceof AnyType || value_type instanceof AnyType) {
|
|
// everything is assignable to or from AnyType
|
|
is_assignable = true;
|
|
} else if (dest_type.rawTypeSignature === 'Ljava/lang/Object;') {
|
|
// everything is assignable to Object
|
|
is_assignable = true;
|
|
} else if (value_type instanceof PrimitiveType) {
|
|
// primitive values can only be assigned to wider primitives or their class equivilents
|
|
is_assignable = valid_primitive_types.from[value_type.typeSignature].test(dest_type.typeSignature);
|
|
} else if (dest_type instanceof PrimitiveType) {
|
|
// primitive variables can only be assigned from narrower primitives or their class equivilents
|
|
is_assignable = valid_primitive_types.to[dest_type.typeSignature].test(value_type.typeSignature);
|
|
} else if (value_type instanceof NullType) {
|
|
// null is assignable to any non-primitive
|
|
is_assignable = !(dest_type instanceof PrimitiveType);
|
|
} else if (value_type instanceof ArrayType) {
|
|
// arrays are assignable to other arrays with the same dimensionality and type-assignable bases
|
|
is_assignable = dest_type instanceof ArrayType
|
|
&& dest_type.arrdims === value_type.arrdims
|
|
&& isTypeAssignable(dest_type.base, value_type.base);
|
|
} else if (value_type instanceof CEIType && dest_type instanceof CEIType) {
|
|
// class/interfaces types are assignable to any class/interface types in their inheritence tree
|
|
const valid_types = getTypeInheritanceList(value_type);
|
|
is_assignable = valid_types.includes(dest_type);
|
|
if (!is_assignable) {
|
|
// generic types are also assignable to their raw counterparts
|
|
const valid_raw_types = valid_types.map(t => t.getRawType());
|
|
is_assignable = valid_raw_types.includes(dest_type);
|
|
if (!is_assignable) {
|
|
// generic types are also assignable to compatible wildcard type bounds
|
|
const raw_type = valid_raw_types.find(rt => rt.rawTypeSignature === dest_type.rawTypeSignature);
|
|
if (raw_type instanceof CEIType && raw_type.typeVariables.length === value_type.typeVariables.length) {
|
|
is_assignable = dest_type.typeVariables.every((dest_tv, idx) => isTypeArgumentCompatible(dest_tv, value_type.typeVariables[idx].type));
|
|
}
|
|
}
|
|
}
|
|
} else if (dest_type instanceof TypeVariableType) {
|
|
is_assignable = !(value_type instanceof PrimitiveType || value_type instanceof NullType);
|
|
}
|
|
return is_assignable;
|
|
}
|
|
|
|
/**
|
|
* @param {TypeVariable} dest_typevar
|
|
* @param {JavaType} value_typevar_type
|
|
*/
|
|
function isTypeArgumentCompatible(dest_typevar, value_typevar_type) {
|
|
if (dest_typevar.type instanceof WildcardType) {
|
|
if (!dest_typevar.type.bound) {
|
|
// unbounded wildcard types are compatible with everything
|
|
return true;
|
|
}
|
|
if (dest_typevar.type.bound.type === value_typevar_type) {
|
|
return true;
|
|
}
|
|
switch (dest_typevar.type.bound.kind) {
|
|
case 'extends':
|
|
return isTypeAssignable(dest_typevar.type.bound.type, value_typevar_type);
|
|
case 'super':;
|
|
return isTypeAssignable(value_typevar_type, dest_typevar.type.bound.type);
|
|
}
|
|
return false;
|
|
}
|
|
if (value_typevar_type instanceof TypeVariableType) {
|
|
// inferred type arguments of the form `x = List<>` are compatible with every destination type variable
|
|
return value_typevar_type.typeVariable instanceof InferredTypeArgument;
|
|
}
|
|
return isTypeAssignable(dest_typevar.type, value_typevar_type);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {ResolvedValue} value
|
|
* @param {() => Token[]} tokens
|
|
* @param {ParseProblem[]} problems
|
|
*/
|
|
function checkBooleanBranchCondition(value, tokens, problems) {
|
|
if (value instanceof JavaType) {
|
|
if (!isTypeAssignable(PrimitiveType.map.Z, value)) {
|
|
problems.push(ParseProblem.Error(tokens(), `Boolean expression expected, but type '${value.fullyDottedTypeName}' found.`));
|
|
}
|
|
return;
|
|
}
|
|
problems.push(ParseProblem.Error(tokens(), `Boolean expression expected.`));
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {CEIType} type
|
|
*/
|
|
function getTypeInheritanceList(type) {
|
|
const types = {
|
|
/** @type {JavaType[]} */
|
|
list: [type],
|
|
/** @type {Set<JavaType>} */
|
|
done: new Set(),
|
|
};
|
|
let object = null;
|
|
for (let type; type = types.list.shift(); ) {
|
|
// always add Object last
|
|
if (type.rawTypeSignature === 'Ljava/lang/Object;') {
|
|
object = type;
|
|
continue;
|
|
}
|
|
if (types.done.has(type)) {
|
|
continue;
|
|
}
|
|
types.done.add(type);
|
|
if (type instanceof CEIType)
|
|
types.list.push(...type.supers);
|
|
}
|
|
if (object) {
|
|
types.done.add(object);
|
|
}
|
|
return Array.from(types.done);
|
|
}
|
|
|
|
exports.checkArrayIndex = checkArrayIndex;
|
|
exports.checkAssignment = checkAssignment;
|
|
exports.checkBooleanBranchCondition = checkBooleanBranchCondition;
|
|
exports.checkTypeAssignable = checkTypeAssignable;
|
|
exports.getTypeInheritanceList = getTypeInheritanceList;
|
|
exports.isTypeAssignable = isTypeAssignable;
|