Implement subtyping for primitive types in templates

This commit is contained in:
Manuel Hässig 2026-01-21 16:47:28 +01:00
parent b7346c307f
commit a0ebfef24b
3 changed files with 38 additions and 7 deletions

View File

@ -129,8 +129,8 @@ public final class Operations {
ops.add(Expression.make(type, "(", type, " + ", type, ")"));
ops.add(Expression.make(type, "(", type, " - ", type, ")"));
ops.add(Expression.make(type, "(", type, " * ", type, ")"));
ops.add(Expression.make(type, "(", type, " / ", type, ")"));
ops.add(Expression.make(type, "(", type, " % ", type, ")"));
ops.add(Expression.make(type, "(", type, " / ", type, ")", WITH_ARITHMETIC_EXCEPTION));
ops.add(Expression.make(type, "(", type, " % ", type, ")", WITH_ARITHMETIC_EXCEPTION));
// Relational / Comparison Operators
ops.add(Expression.make(BOOLEANS, "(", type, " == ", type, ")"));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -71,7 +71,22 @@ public final class PrimitiveType implements CodeGenerationDataNameType {
@Override
public boolean isSubtypeOf(DataName.Type other) {
return (other instanceof PrimitiveType pt) && pt.kind == kind;
// Implement other >: this according to JLS §4.10.1.
if (other instanceof PrimitiveType pt) {
if (pt.kind == Kind.BOOLEAN || kind == Kind.BOOLEAN) {
// Boolean does not have a supertype and only itself as a subtype.
return pt.kind == kind;
}
if (pt.kind == Kind.CHAR || kind == Kind.CHAR) {
// Char does not have a subtype, but .
// The following is correct for the subtype relation to floats, since chars are 16 bits wide and floats 32 bits or more.
return pt.kind == kind || (pt.byteSize() > this.byteSize() && this.kind != Kind.BYTE);
}
return (pt.isFloating() && !this.isFloating()) || // Due to float >: long, all integers are subtypes of floating point types.
(pt.isFloating() == this.isFloating() && pt.byteSize() >= this.byteSize()); // Generally, narrower types are subtypes of wider types.
}
return false;
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,6 +48,7 @@ import static compiler.lib.template_framework.Template.let;
import static compiler.lib.template_framework.Template.$;
import static compiler.lib.template_framework.Template.addDataName;
import static compiler.lib.template_framework.DataName.Mutability.MUTABLE;
import static compiler.lib.template_framework.DataName.Mutability.MUTABLE_OR_IMMUTABLE;
import compiler.lib.template_framework.library.Hooks;
import compiler.lib.template_framework.library.CodeGenerationDataNameType;
@ -129,7 +130,8 @@ public class TestPrimitiveTypes {
}
// Finally, test the type by creating some DataNames (variables), and sampling
// from them. There should be no cross-over between the types.
// from them. Sampling exactly should not lead to any conversion and sampling
// subtypes should only lead to widening conversions.
// IMPORTANT: since we are adding the DataName via an inserted Template, we
// must chose a "transparentScope", so that the DataName escapes. If we
// instead chose "scope", the test would fail, because it later
@ -150,6 +152,14 @@ public class TestPrimitiveTypes {
"""
));
var assignmentTemplate = Template.make("lhsType", (PrimitiveType lhsType) -> scope(
dataNames(MUTABLE).exactOf(lhsType).sampleAndLetAs("lhs"),
dataNames(MUTABLE_OR_IMMUTABLE).subtypeOf(lhsType).sampleAndLetAs("rhs"),
"""
#lhs = #rhs;
"""
));
var namesTemplate = Template.make(() -> scope(
"""
public static void test_names() {
@ -161,10 +171,16 @@ public class TestPrimitiveTypes {
).toList()
),
"""
// Now sample:
// Sample exactly:
""",
Collections.nCopies(10,
CodeGenerationDataNameType.PRIMITIVE_TYPES.stream().map(sampleTemplate::asToken).toList()
),
"""
// Sample subtypes:
""",
Collections.nCopies(10,
CodeGenerationDataNameType.PRIMITIVE_TYPES.stream().map(assignmentTemplate::asToken).toList()
)
)),
"""