From f33fea289f01c7dd5a071562de6356913ec17adf Mon Sep 17 00:00:00 2001 From: Gene Gleyzer Date: Tue, 31 May 2022 16:32:28 -0400 Subject: [PATCH] Add a compiler check for unresolved method type parameters --- .../compiler/ast/InvocationExpression.java | 34 ++++++++++++------- .../main/x/ecstasy/annotations/LinkedList.x | 4 +-- .../src/main/x/ecstasy/collections/Tuple.x | 17 ++++++---- lib_ecstasy/src/main/x/ecstasy/reflect/Ref.x | 4 +-- lib_ecstasy/src/main/x/ecstasy/reflect/Type.x | 6 ++-- lib_json/src/main/x/json/ObjectOutputStream.x | 9 ++--- lib_web/src/main/x/web/DefaultUriRouteMatch.x | 6 ++-- .../main/x/web/binder/RequestBinderRegistry.x | 6 ++-- lib_web/src/main/x/web/codec/JsonCodec.x | 4 +-- 9 files changed, 53 insertions(+), 37 deletions(-) diff --git a/javatools/src/main/java/org/xvm/compiler/ast/InvocationExpression.java b/javatools/src/main/java/org/xvm/compiler/ast/InvocationExpression.java index 9de70ef573..53712fb8c6 100644 --- a/javatools/src/main/java/org/xvm/compiler/ast/InvocationExpression.java +++ b/javatools/src/main/java/org/xvm/compiler/ast/InvocationExpression.java @@ -891,34 +891,44 @@ else if (m_fBjarne) return null; } - Argument[] aargTypeParam = new Argument[mapTypeParams.size()]; - int ix = 0; + Argument[] aargTypeParam = new Argument[mapTypeParams.size()]; + List listUnresolved = null; + int iArg = 0; for (TypeConstant typeArg : mapTypeParams.values()) { - if (typeArg.containsUnresolved()) + if (typeArg.containsUnresolved() || typeArg.equals(pool.typeObject())) { - log(errs, Severity.ERROR, Compiler.TYPE_PARAMS_UNRESOLVABLE, - method.getParam(ix).getName()); - return null; + if (listUnresolved == null) + { + listUnresolved = new ArrayList<>(); + } + listUnresolved.add(method.getParam(iArg++).getName()); + continue; } - TypeConstant typeParam = idMethod.getRawParams()[ix].getParamType(0); + TypeConstant typeConstraint = idMethod.getRawParams()[iArg].getParamType(0); // there's a possibility that type parameter constraints refer to // previous type parameters, for example: // foo(T1 v1, T2 v2) {...} - if (typeParam.containsTypeParameter(true)) + if (typeConstraint.containsTypeParameter(true)) { - typeParam = typeParam.resolveGenerics(pool, mapTypeParams::get); + typeConstraint = typeConstraint.resolveGenerics(pool, mapTypeParams::get); } - if (!typeArg.isA(typeParam)) + if (!typeArg.isA(typeConstraint)) { log(errs, Severity.ERROR, Compiler.WRONG_TYPE, - typeParam.getValueString(), typeArg.getValueString()); + typeConstraint.getValueString(), typeArg.getValueString()); return null; } - aargTypeParam[ix++] = typeArg.getType(); + aargTypeParam[iArg++] = typeArg.getType(); + } + + if (listUnresolved != null) + { + log(errs, Severity.ERROR, Compiler.TYPE_PARAMS_UNRESOLVABLE, listUnresolved); + return null; } m_aargTypeParams = aargTypeParam; } diff --git a/lib_ecstasy/src/main/x/ecstasy/annotations/LinkedList.x b/lib_ecstasy/src/main/x/ecstasy/annotations/LinkedList.x index ed719a7ec1..673dbb25be 100644 --- a/lib_ecstasy/src/main/x/ecstasy/annotations/LinkedList.x +++ b/lib_ecstasy/src/main/x/ecstasy/annotations/LinkedList.x @@ -512,8 +512,8 @@ mixin LinkedList { Object that = iter.outer; if (that.is(LinkedList), - Property thisProp := this.isProperty(), - Property thatProp := that.isProperty(), + Property thisProp := this.isProperty(), + Property thatProp := that.isProperty(), &thisProp == &thatProp) { Element? thatNode = that.writeConfig(); diff --git a/lib_ecstasy/src/main/x/ecstasy/collections/Tuple.x b/lib_ecstasy/src/main/x/ecstasy/collections/Tuple.x index 601a03f780..08f3ca2916 100644 --- a/lib_ecstasy/src/main/x/ecstasy/collections/Tuple.x +++ b/lib_ecstasy/src/main/x/ecstasy/collections/Tuple.x @@ -299,18 +299,23 @@ interface Tuple> for (Int i : [0..c)) { - Type t1 = value1.elementAt(i).actualType; - Type t2 = value2.elementAt(i).actualType; - if (t1 != t2) + val ref1 = value1.elementAt(i); + val ref2 = value2.elementAt(i); + if (ref1 == ref2) { - return False; + // identical references (including two Null values) + continue; } - if (!t1.DataType.equals(value1[i], value2[i])) + val val1 = ref1.get(); + val val2 = ref2.get(); + if (val1 == Null || val2 == Null // eliminate either-is-Null + || (ref1.Referent-Nullable) != (ref2.Referent-Nullable) // so ignore type Nullable + || val1.as(ref1.Referent) != val2.as(ref1.Referent)) { return False; } } return True; } - } + } \ No newline at end of file diff --git a/lib_ecstasy/src/main/x/ecstasy/reflect/Ref.x b/lib_ecstasy/src/main/x/ecstasy/reflect/Ref.x index 186057e278..c1493ccd36 100644 --- a/lib_ecstasy/src/main/x/ecstasy/reflect/Ref.x +++ b/lib_ecstasy/src/main/x/ecstasy/reflect/Ref.x @@ -247,7 +247,7 @@ interface Ref /** * The [Property] corresponding to this reference, if this is a reference to a property value. */ - conditional (Property>, Container) isProperty(); + conditional (Property>, Object) isProperty(); /** * The reference annotations. These are the annotations that apply to the reference itself (i.e. @@ -310,4 +310,4 @@ interface Ref return value1 == value2; } } - } + } \ No newline at end of file diff --git a/lib_ecstasy/src/main/x/ecstasy/reflect/Type.x b/lib_ecstasy/src/main/x/ecstasy/reflect/Type.x index 4df2214726..c16613abd6 100644 --- a/lib_ecstasy/src/main/x/ecstasy/reflect/Type.x +++ b/lib_ecstasy/src/main/x/ecstasy/reflect/Type.x @@ -636,7 +636,7 @@ interface Type { if (fn.ParamTypes.size == 1) { - assert fn.ParamTypes[0] == OuterType; + assert fn.ParamTypes[0] == OuterType.DataType; return True, fn.as(function DataType(OuterType)). bind(fn.params[0].as(Parameter), outer) .as(function DataType()); @@ -1165,6 +1165,4 @@ interface Type Type!<> typeActual = this.DataType; return new iterators.EmptyIterator().as(Iterator); } - } - - + } \ No newline at end of file diff --git a/lib_json/src/main/x/json/ObjectOutputStream.x b/lib_json/src/main/x/json/ObjectOutputStream.x index 8d494b2cde..3777a13558 100644 --- a/lib_json/src/main/x/json/ObjectOutputStream.x +++ b/lib_json/src/main/x/json/ObjectOutputStream.x @@ -672,10 +672,11 @@ class ObjectOutputStream(Schema schema, Writer writer) * * @return this */ - protected PointerAwareDocOutput writePointerOrValue((String | Int)? id, - Object value, - function void(String) writePointer, - function void() writeValue) + protected PointerAwareDocOutput writePointerOrValue( + (String | Int)? id, + Serializable value, + function void(String) writePointer, + function void() writeValue) { Boolean alreadyInside = inside; if (alreadyInside || value.is(Primitive)) diff --git a/lib_web/src/main/x/web/DefaultUriRouteMatch.x b/lib_web/src/main/x/web/DefaultUriRouteMatch.x index 0181599e4c..9f04344d27 100644 --- a/lib_web/src/main/x/web/DefaultUriRouteMatch.x +++ b/lib_web/src/main/x/web/DefaultUriRouteMatch.x @@ -129,13 +129,13 @@ class DefaultUriRouteMatch if (Object paramValue := parameterValues.get(name)) { - parameters = parameters.add(convert(param, paramValue)); + parameters = parameters.add(convert(param, paramValue).as(param.ParamType)); } else if (Object variableValue := variableValues.get(name)) { - parameters = parameters.add(convert(param, variableValue)); + parameters = parameters.add(convert(param, variableValue).as(param.ParamType)); } - else if (Object defaultValue := param.defaultValue()) + else if (param.ParamType defaultValue := param.defaultValue()) { parameters = parameters.add(defaultValue); } diff --git a/lib_web/src/main/x/web/binder/RequestBinderRegistry.x b/lib_web/src/main/x/web/binder/RequestBinderRegistry.x index 8bd26401eb..f312b634dc 100644 --- a/lib_web/src/main/x/web/binder/RequestBinderRegistry.x +++ b/lib_web/src/main/x/web/binder/RequestBinderRegistry.x @@ -94,7 +94,9 @@ class RequestBinderRegistry if (String name := p.hasName(), ParameterBinder binder := findParameterBinder(p, req)) { - BindingResult result = binder.bind(p, req); + Type paramType = p.ParamType; + BindingResult result = + binder.bind(p.as(Parameter), req); if (result.bound) { arguments.put(name, result.value); @@ -120,4 +122,4 @@ class RequestBinderRegistry ")".appendTo(buf); return buf; } - } + } \ No newline at end of file diff --git a/lib_web/src/main/x/web/codec/JsonCodec.x b/lib_web/src/main/x/web/codec/JsonCodec.x index 9a52e87ae8..f4643e34e2 100644 --- a/lib_web/src/main/x/web/codec/JsonCodec.x +++ b/lib_web/src/main/x/web/codec/JsonCodec.x @@ -41,7 +41,7 @@ const JsonCodec @Override ObjectType decode(Type type, InputStream in) { - assert Mapping mapper := schema.findMapping(type); + assert Mapping mapper := schema.findMapping(type.DataType); ObjectInputStream o_in = schema.createObjectInput(new UTF8Reader(in)).as(ObjectInputStream); ElementInputStream e_in = o_in.ensureElementInput(); return mapper.read(e_in).as(ObjectType); @@ -62,4 +62,4 @@ const JsonCodec schema.createObjectOutput(new UTF8Writer(out)).write(value); } } - } + } \ No newline at end of file