From 5b29b9998d3ee9d6ce9b735f3f16db604c10c368 Mon Sep 17 00:00:00 2001 From: Dave Holoway Date: Thu, 11 Jun 2020 13:44:59 +0100 Subject: [PATCH] add support for generic inferred-type arguments --- langserver/java/body-parser3.js | 7 ++++++- langserver/java/typeident.js | 36 ++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/langserver/java/body-parser3.js b/langserver/java/body-parser3.js index 67ea8f4..d89b690 100644 --- a/langserver/java/body-parser3.js +++ b/langserver/java/body-parser3.js @@ -4,7 +4,8 @@ * * Each token also contains detailed state information used for completion suggestions. */ -const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, NullType, WildcardType, TypeVariable, Field, Method, ReifiedMethod, Parameter, Constructor, signatureToType } = require('java-mti'); +const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, NullType, WildcardType, TypeVariableType, + TypeVariable, InferredTypeArgument, 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'); @@ -1269,6 +1270,10 @@ function isTypeArgumentCompatible(dest_typevar, value_typevar_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 dest_typevar.type === value_typevar_type; } diff --git a/langserver/java/typeident.js b/langserver/java/typeident.js index 626f511..efc846d 100644 --- a/langserver/java/typeident.js +++ b/langserver/java/typeident.js @@ -89,26 +89,34 @@ function typeIdent(tokens, scope, imports, typemap, allow_array_qualifiers = tru * @param {Map} typemap */ function genericTypeArgs(tokens, types, scope, imports, typemap) { - if (!tokens.isValue('>')) { - const type_arguments = typeIdentList(tokens, scope, imports, typemap); + if (tokens.isValue('>')) { + // <> operator - build new types with inferred type arguments types.forEach((t,i,arr) => { if (t instanceof CEIType) { - let specialised = t.specialise(type_arguments); - if (typemap.has(specialised.shortSignature)) { - arr[i] = typemap.get(specialised.shortSignature); - return; - } - typemap.set(specialised.shortSignature, specialised); + let specialised = t.makeInferredTypeArgs(); arr[i] = specialised; } }); - if (/>>>?/.test(tokens.current.value)) { - // we need to split >> and >>> into separate > tokens to handle things like List> - const new_tokens = tokens.current.value.split('').map((gt,i) => new Token(tokens.current.range.source, tokens.current.range.start + i, 1, 'comparison-operator')); - tokens.splice(tokens.idx, 1, ...new_tokens); - } - tokens.expectValue('>'); + return; } + const type_arguments = typeIdentList(tokens, scope, imports, typemap); + types.forEach((t,i,arr) => { + if (t instanceof CEIType) { + let specialised = t.specialise(type_arguments); + if (typemap.has(specialised.shortSignature)) { + arr[i] = typemap.get(specialised.shortSignature); + return; + } + typemap.set(specialised.shortSignature, specialised); + arr[i] = specialised; + } + }); + if (/>>>?/.test(tokens.current.value)) { + // we need to split >> and >>> into separate > tokens to handle things like List> + const new_tokens = tokens.current.value.split('').map((gt,i) => new Token(tokens.current.range.source, tokens.current.range.start + i, 1, 'comparison-operator')); + tokens.splice(tokens.idx, 1, ...new_tokens); + } + tokens.expectValue('>'); } /**