Make the example fail
Some checks failed
Build and Test with Maven / Build-and-test-with-Maven (push) Failing after 5m47s

This commit is contained in:
Daniel Holle 2024-12-11 13:29:14 +01:00
parent 09c483542d
commit b76e1e46f0
3 changed files with 70 additions and 30 deletions

View File

@ -17,6 +17,7 @@ import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*; import de.dhbwstuttgart.typeinference.result.*;
import java.lang.annotation.Target;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -163,6 +164,7 @@ public class ASTToTargetAST {
for (var i = 0; i < signature.parameters().size(); i++) { for (var i = 0; i < signature.parameters().size(); i++) {
var p1 = signature.parameters().get(i).pattern().type(); var p1 = signature.parameters().get(i).pattern().type();
var p2 = other.signature.parameters().get(i).pattern().type(); var p2 = other.signature.parameters().get(i).pattern().type();
if (p1 instanceof TargetGenericType && p2 instanceof TargetGenericType) continue;
if (!p1.equals(p2) && commonSuperInterfaceTypes(p1, p2).isEmpty()) return false; if (!p1.equals(p2) && commonSuperInterfaceTypes(p1, p2).isEmpty()) return false;
} }
return true; return true;
@ -176,6 +178,7 @@ public class ASTToTargetAST {
// This finds a common sealed interface type to group together methods that use different records // This finds a common sealed interface type to group together methods that use different records
private List<ClassOrInterface> commonSuperInterfaceTypes(TargetType a, TargetType b) { private List<ClassOrInterface> commonSuperInterfaceTypes(TargetType a, TargetType b) {
if (a instanceof TargetGenericType && b instanceof TargetGenericType) return List.of(ASTFactory.createClass(Object.class));
if (a instanceof TargetRefType ta && b instanceof TargetRefType tb) { if (a instanceof TargetRefType ta && b instanceof TargetRefType tb) {
var res = new HashSet<ClassOrInterface>(); var res = new HashSet<ClassOrInterface>();
@ -359,14 +362,26 @@ public class ASTToTargetAST {
} }
} }
private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetExpression> params, List<TargetComplexPattern> patterns, List<TargetMethod> methods, TargetType classType) { private TargetType unwrap(TargetType type) {
if (type instanceof TargetRefType ref) {
if (!ref.params().isEmpty()) return new TargetRefType(ref.name());
}
return type;
}
private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List<TargetLocalVar> params, List<TargetPattern> patterns, List<TargetMethod> methods, TargetType classType) {
if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading"); if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading");
if (methods.size() == 1) { if (methods.size() == 1) {
var method = methods.getFirst(); var method = methods.getFirst();
var mParams = new ArrayList<TargetExpression>();
for (var i = 0; i < params.size(); i++) {
var tpe = method.signature().parameters().get(i).pattern().type();
mParams.add(new TargetLocalVar(tpe, params.get(i).name()));
}
TargetExpression caseBody = new TargetMethodCall( TargetExpression caseBody = new TargetMethodCall(
method.signature().returnType(), method.signature().returnType(),
new TargetThis(classType), new TargetThis(classType),
params, mParams,
classType, classType,
method.name(), method.name(),
false, false, method.isPrivate() false, false, method.isPrivate()
@ -378,7 +393,7 @@ public class ASTToTargetAST {
} }
var cases = new ArrayList<TargetSwitch.Case>(); var cases = new ArrayList<TargetSwitch.Case>();
var usedPatterns = new HashSet<TargetPattern>(); var usedPatterns = new HashSet<TargetType>();
for (var method : methods) { for (var method : methods) {
var patternsRec = new ArrayList<>(patterns); var patternsRec = new ArrayList<>(patterns);
@ -386,33 +401,29 @@ public class ASTToTargetAST {
TargetExpression expr = null; TargetExpression expr = null;
var i = 0; var i = 0;
for (var param : method.signature().parameters()) { for (var param : method.signature().parameters()) {
if (param.pattern() instanceof TargetComplexPattern pat) {
if (i == offset) { if (i == offset) {
patternsRec.add(pat); patternsRec.add(param.pattern());
} }
if (i > offset) { if (i > offset) {
// Find next pattern // Find next pattern
var pattern = param.pattern(); expr = params.get(i);
expr = new TargetLocalVar(pattern.type(), pattern.name());
break; break;
} }
i++; i++;
} }
}
var lastPattern = patternsRec.getLast(); var lastPattern = patternsRec.getLast();
if (usedPatterns.contains(lastPattern)) continue; var type = unwrap(lastPattern.type());
usedPatterns.add(lastPattern); if (usedPatterns.contains(type)) continue;
usedPatterns.add(type);
var candidates = methods.stream().filter(m -> { var candidates = methods.stream().filter(m -> {
var j = 0; var j = 0;
for (var param : m.signature().parameters()) { for (var param : m.signature().parameters()) {
if (j >= patternsRec.size()) return true; if (j >= patternsRec.size()) return true;
if (param.pattern() instanceof TargetComplexPattern) { if (!patternsRec.get(j).type().equals(param.pattern().type())) return false;
if (!patternsRec.get(j).equals(param.pattern())) return false;
j++; j++;
} }
}
return true; return true;
}).toList(); }).toList();
@ -430,6 +441,7 @@ public class ASTToTargetAST {
if (overloadedMethods.size() <= 1) return overloadedMethods; if (overloadedMethods.size() <= 1) return overloadedMethods;
// Check if we have a pattern as a parameter // Check if we have a pattern as a parameter
var firstMethod = overloadedMethods.getFirst(); var firstMethod = overloadedMethods.getFirst();
var secondMethod = overloadedMethods.get(1);
if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods; if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods;
// Rename existing methods // Rename existing methods
@ -439,23 +451,41 @@ public class ASTToTargetAST {
res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature())); res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature()));
} }
var signatureParams = firstMethod.signature().parameters().stream().map(p -> { var signatureParams = new ArrayList<MethodParameter>();
if (p.pattern() instanceof TargetComplexPattern pat) { for (var i = 0; i < firstMethod.signature().parameters().size(); i++) {
return new MethodParameter(pat.type(), pat.name()); var p1 = firstMethod.signature().parameters().get(i).pattern();
var t1 = p1.type();
var t2 = secondMethod.signature().parameters().get(i).pattern().type();
var commonSubTypes = new HashSet<>(commonSuperInterfaceTypes(t1, t2));
for (var m : overloadedMethods.subList(2, overloadedMethods.size())) {
var t3 = m.signature().parameters().get(i).pattern().type();
commonSubTypes.retainAll(commonSuperInterfaceTypes(t1, t3));
} }
return p; if (commonSubTypes.size() != 1) throw new DebugException("Invalid overload");
}).toList(); // TODO accept multiple types
var parameters = firstMethod.signature().parameters().stream().map( p -> (TargetExpression) new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList(); var superType = commonSubTypes.iterator().next();
String name;
if (p1 instanceof TargetComplexPattern) name = "__var" + i;
else name = p1.name();
signatureParams.add(new MethodParameter(new TargetRefType(superType.getClassName().toString()), name));
}
var commonSubTypes = new HashSet<>(commonSuperInterfaceTypes(firstMethod.signature().returnType(), secondMethod.signature().returnType()));
for (var m : overloadedMethods.subList(2, overloadedMethods.size())) {
commonSubTypes.retainAll(commonSuperInterfaceTypes(firstMethod.signature().returnType(), m.signature().returnType()));
}
var returnType = commonSubTypes.isEmpty() ? TargetType.Object : new TargetRefType(commonSubTypes.iterator().next().getClassName().toString());
var parameters = signatureParams.stream().map( p -> new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList();
//var patterns = List.of((TargetComplexPattern) firstMethod.signature().parameters().stream() //var patterns = List.of((TargetComplexPattern) firstMethod.signature().parameters().stream()
// .filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern()); // .filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern());
var firstPattern = firstMethod.signature().parameters().stream().filter(p -> p.pattern() instanceof TargetComplexPattern).findFirst().orElseThrow().pattern();
// Generate dispatch method // Generate dispatch method
var classType = new TargetRefType(clazz.getClassName().getClassName()); var classType = new TargetRefType(clazz.getClassName().getClassName());
var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(firstPattern.type(), firstPattern.name()), parameters, List.of(), res, classType); var stmt = generatePatternOverloadsRec(0, new TargetLocalVar(signatureParams.getFirst().pattern().type(), signatureParams.getFirst().pattern().name()), parameters, List.of(), res, classType);
var block = new TargetBlock(List.of(stmt)); var block = new TargetBlock(List.of(stmt));
var signature = new TargetMethod.Signature(firstMethod.signature().generics(), signatureParams, firstMethod.signature().returnType()); var signature = new TargetMethod.Signature(Set.of(), signatureParams, returnType);
var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, signature, firstMethod.txSignature()); var bridgeMethod = new TargetMethod(firstMethod.access(), firstMethod.name(), block, signature, firstMethod.txSignature());
res.add(bridgeMethod); res.add(bridgeMethod);

View File

@ -118,7 +118,7 @@ public class TYPE {
FormalParameter param = (FormalParameter) allClass.getConstructors().getFirst().getParameterList().getParameterAt(counter); FormalParameter param = (FormalParameter) allClass.getConstructors().getFirst().getParameterList().getParameterAt(counter);
FieldAssumption assumption = new FieldAssumption(param.getName(), allClass, param.getType(), blockInformation.getCurrentTypeScope()); FieldAssumption assumption = new FieldAssumption(param.getName(), allClass, param.getType(), blockInformation.getCurrentTypeScope());
var fieldCons = new Pair(el.getType(), assumption.getType(resolver), PairOperator.SMALLERDOT); var fieldCons = new Pair(el.getType(), assumption.getType(resolver), PairOperator.EQUALSDOT);
var recvCons = new Pair(refType, assumption.getReceiverType(resolver), PairOperator.EQUALSDOT); var recvCons = new Pair(refType, assumption.getReceiverType(resolver), PairOperator.EQUALSDOT);
constraintSet.addUndConstraint(fieldCons); constraintSet.addUndConstraint(fieldCons);
constraintSet.addUndConstraint(recvCons); constraintSet.addUndConstraint(recvCons);

View File

@ -930,6 +930,16 @@ public class TestComplete {
var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PatternMatchingListAppend.jav"); var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PatternMatchingListAppend.jav");
var clazz = classFiles.get("PatternMatchingListAppend"); var clazz = classFiles.get("PatternMatchingListAppend");
var instance = clazz.getDeclaredConstructor().newInstance(); var instance = clazz.getDeclaredConstructor().newInstance();
var Cons = classFiles.get("Cons");
var Empty = classFiles.get("Empty");
var List = classFiles.get("List");
var ConsCtor = Cons.getDeclaredConstructor(Object.class, List);
var EmptyCtor = Empty.getDeclaredConstructor();
var list1 = ConsCtor.newInstance(1, ConsCtor.newInstance(2, ConsCtor.newInstance(3, EmptyCtor.newInstance())));
var list2 = ConsCtor.newInstance(4, ConsCtor.newInstance(5, ConsCtor.newInstance(6, EmptyCtor.newInstance())));
} }
@Test @Test