Skip to content

Commit

Permalink
Add a compiler check for unresolved method type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Gene Gleyzer committed May 31, 2022
1 parent 4fe399b commit f33fea2
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> 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:
// <T1 extends Base, T2 extends T1> 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;
}
Expand Down
4 changes: 2 additions & 2 deletions lib_ecstasy/src/main/x/ecstasy/annotations/LinkedList.x
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,8 @@ mixin LinkedList<Element>
{
Object that = iter.outer;
if (that.is(LinkedList),
Property<Object> thisProp := this.isProperty(),
Property<Object> thatProp := that.isProperty(),
Property thisProp := this.isProperty(),
Property thatProp := that.isProperty(),
&thisProp == &thatProp)
{
Element? thatNode = that.writeConfig();
Expand Down
17 changes: 11 additions & 6 deletions lib_ecstasy/src/main/x/ecstasy/collections/Tuple.x
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,23 @@ interface Tuple<ElementTypes extends Tuple<ElementTypes>>

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;
}
}
}
4 changes: 2 additions & 2 deletions lib_ecstasy/src/main/x/ecstasy/reflect/Ref.x
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ interface Ref<Referent>
/**
* The [Property] corresponding to this reference, if this is a reference to a property value.
*/
<Container> conditional (Property<Container, Referent, Ref<Referent>>, Container) isProperty();
conditional (Property<Object, Referent, Ref<Referent>>, Object) isProperty();

/**
* The reference annotations. These are the annotations that apply to the reference itself (i.e.
Expand Down Expand Up @@ -310,4 +310,4 @@ interface Ref<Referent>
return value1 == value2;
}
}
}
}
6 changes: 2 additions & 4 deletions lib_ecstasy/src/main/x/ecstasy/reflect/Type.x
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ interface Type<DataType, OuterType>
{
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<OuterType>), outer)
.as(function DataType());
Expand Down Expand Up @@ -1165,6 +1165,4 @@ interface Type<DataType, OuterType>
Type!<> typeActual = this.DataType;
return new iterators.EmptyIterator<typeActual.DataType>().as(Iterator<DataType>);
}
}


}
9 changes: 5 additions & 4 deletions lib_json/src/main/x/json/ObjectOutputStream.x
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Serializable> PointerAwareDocOutput writePointerOrValue(
(String | Int)? id,
Serializable value,
function void(String) writePointer,
function void() writeValue)
{
Boolean alreadyInside = inside;
if (alreadyInside || value.is(Primitive))
Expand Down
6 changes: 3 additions & 3 deletions lib_web/src/main/x/web/DefaultUriRouteMatch.x
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
6 changes: 4 additions & 2 deletions lib_web/src/main/x/web/binder/RequestBinderRegistry.x
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ class RequestBinderRegistry
if (String name := p.hasName(),
ParameterBinder<HttpRequest> binder := findParameterBinder(p, req))
{
BindingResult result = binder.bind(p, req);
Type paramType = p.ParamType;
BindingResult<paramType.DataType> result =
binder.bind(p.as(Parameter<paramType.DataType>), req);
if (result.bound)
{
arguments.put(name, result.value);
Expand All @@ -120,4 +122,4 @@ class RequestBinderRegistry
")".appendTo(buf);
return buf;
}
}
}
4 changes: 2 additions & 2 deletions lib_web/src/main/x/web/codec/JsonCodec.x
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const JsonCodec
@Override
<ObjectType> ObjectType decode<ObjectType>(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);
Expand All @@ -62,4 +62,4 @@ const JsonCodec
schema.createObjectOutput(new UTF8Writer(out)).write(value);
}
}
}
}

0 comments on commit f33fea2

Please sign in to comment.