From 309cc4710735de7dcaea9efea70c375f8b77640b Mon Sep 17 00:00:00 2001 From: Dave Holoway Date: Wed, 10 Jun 2020 11:57:16 +0100 Subject: [PATCH] specialise methods with type variables --- langserver/java/body-parser3.js | 25 ++++++++++++------------- langserver/java/source-type.js | 3 ++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/langserver/java/body-parser3.js b/langserver/java/body-parser3.js index e85bd52..7e6b192 100644 --- a/langserver/java/body-parser3.js +++ b/langserver/java/body-parser3.js @@ -4,7 +4,7 @@ * * Each token also contains detailed state information used for completion suggestions. */ -const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, WildcardType, TypeVariable, Field, Method, Parameter, Constructor, signatureToType } = require('java-mti'); +const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, NullType, WildcardType, TypeVariable, Field, Method, ReifiedMethod, Parameter, Constructor, signatureToType } = require('java-mti'); const { SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type'); const ResolvedImport = require('./parsetypes/resolved-import'); const ParseProblem = require('./parsetypes/parse-problem'); @@ -1768,11 +1768,20 @@ function arrayElementOrConstructor(tokens, open_array, matches, index) { */ function methodCallExpression(tokens, instance, call_arguments, typemap) { const ident = `${instance.source}(${call_arguments.map(arg => arg.source).join(',')})`; - + // method call resolving is painful in Java - we need to match arguments against // possible types in the call, but this must include matching against inherited types and choosing the // most-specific match - const methods = instance.methods.filter(m => isCallCompatible(m, call_arguments)); + const methods = []; + instance.methods.forEach(m => { + if (m.typeVariables.length) { + // if the method is declared with type variables, specialise it based upon the argument types + m = ReifiedMethod.build(m, call_arguments.map(arg => arg.variables[0].type)); + } + if (isCallCompatible(m, call_arguments)) { + methods.push(m); + } + }); const types = instance.types.filter(t => { // interfaces use Object constructors const type = t.typeKind === 'interface' @@ -1859,16 +1868,6 @@ function getTypeInheritanceList(type) { return Array.from(types.done); } -class NullType extends JavaType { - constructor() { - super('class', [], ''); - super.simpleTypeName = 'null'; - } - get typeSignature() { - return 'null'; - } -} - /** * @param {ResolvedIdent} matches diff --git a/langserver/java/source-type.js b/langserver/java/source-type.js index d6f515e..2a78978 100644 --- a/langserver/java/source-type.js +++ b/langserver/java/source-type.js @@ -1,4 +1,4 @@ -const { JavaType, CEIType, PrimitiveType, Constructor, Method, MethodBase, Field, Parameter, TypeVariable, UnresolvedType, signatureToType } = require('java-mti'); +const { JavaType, ArrayType, CEIType, NullType, PrimitiveType, TypeVariableType, Constructor, Method, MethodBase, Field, Parameter, TypeVariable, UnresolvedType, signatureToType } = require('java-mti'); const { ModuleBlock, TypeDeclBlock, FieldBlock, ConstructorBlock, MethodBlock, InitialiserBlock, ParameterBlock, TextBlock } = require('./parser9'); /** @@ -214,6 +214,7 @@ class SourceMethod extends Method { this._decl = decl; this._parameters = decl.parameters.map((p,i) => new SourceParameter(p)); this._returnType = new ResolvableType(decl); + /** @type {TypeVariable[]} */ this._typevars = decl.typeVariables.map(tv => { const typevar = new TypeVariable(owner, tv.name); // automatically add the Object bound