diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index d5bd882e..217ab74b 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -17,6 +17,7 @@ import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.typeinference.result.*; +import java.lang.annotation.Target; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -163,6 +164,7 @@ public class ASTToTargetAST { for (var i = 0; i < signature.parameters().size(); i++) { var p1 = 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; } return true; @@ -176,6 +178,7 @@ public class ASTToTargetAST { // This finds a common sealed interface type to group together methods that use different records private List 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) { var res = new HashSet(); @@ -359,14 +362,26 @@ public class ASTToTargetAST { } } - private TargetExpression generatePatternOverloadsRec(int offset, TargetExpression switchExpr, List params, List patterns, List 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 params, List patterns, List methods, TargetType classType) { if (methods.isEmpty()) throw new DebugException("Couldn't find a candidate for switch overloading"); if (methods.size() == 1) { var method = methods.getFirst(); + var mParams = new ArrayList(); + 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( method.signature().returnType(), new TargetThis(classType), - params, + mParams, classType, method.name(), false, false, method.isPrivate() @@ -378,7 +393,7 @@ public class ASTToTargetAST { } var cases = new ArrayList(); - var usedPatterns = new HashSet(); + var usedPatterns = new HashSet(); for (var method : methods) { var patternsRec = new ArrayList<>(patterns); @@ -386,32 +401,28 @@ public class ASTToTargetAST { TargetExpression expr = null; var i = 0; for (var param : method.signature().parameters()) { - if (param.pattern() instanceof TargetComplexPattern pat) { - if (i == offset) { - patternsRec.add(pat); - } - if (i > offset) { - // Find next pattern - var pattern = param.pattern(); - expr = new TargetLocalVar(pattern.type(), pattern.name()); - break; - } - i++; + if (i == offset) { + patternsRec.add(param.pattern()); } + if (i > offset) { + // Find next pattern + expr = params.get(i); + break; + } + i++; } var lastPattern = patternsRec.getLast(); - if (usedPatterns.contains(lastPattern)) continue; - usedPatterns.add(lastPattern); + var type = unwrap(lastPattern.type()); + if (usedPatterns.contains(type)) continue; + usedPatterns.add(type); var candidates = methods.stream().filter(m -> { var j = 0; for (var param : m.signature().parameters()) { if (j >= patternsRec.size()) return true; - if (param.pattern() instanceof TargetComplexPattern) { - if (!patternsRec.get(j).equals(param.pattern())) return false; - j++; - } + if (!patternsRec.get(j).type().equals(param.pattern().type())) return false; + j++; } return true; }).toList(); @@ -430,6 +441,7 @@ public class ASTToTargetAST { if (overloadedMethods.size() <= 1) return overloadedMethods; // Check if we have a pattern as a parameter var firstMethod = overloadedMethods.getFirst(); + var secondMethod = overloadedMethods.get(1); if (firstMethod.signature().parameters().stream().noneMatch(mp -> mp.pattern() instanceof TargetComplexPattern)) return overloadedMethods; // Rename existing methods @@ -439,23 +451,41 @@ public class ASTToTargetAST { res.add(new TargetMethod(method.access(), name, method.block(), method.signature(), method.txSignature())); } - var signatureParams = firstMethod.signature().parameters().stream().map(p -> { - if (p.pattern() instanceof TargetComplexPattern pat) { - return new MethodParameter(pat.type(), pat.name()); + var signatureParams = new ArrayList(); + for (var i = 0; i < firstMethod.signature().parameters().size(); i++) { + 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; - }).toList(); - var parameters = firstMethod.signature().parameters().stream().map( p -> (TargetExpression) new TargetLocalVar(p.pattern().type(), p.pattern().name())).toList(); + if (commonSubTypes.size() != 1) throw new DebugException("Invalid overload"); + // TODO accept multiple types + 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() // .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 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 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()); res.add(bridgeMethod); diff --git a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java index 5b38591a..6b591324 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPE.java @@ -118,7 +118,7 @@ public class TYPE { FormalParameter param = (FormalParameter) allClass.getConstructors().getFirst().getParameterList().getParameterAt(counter); 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); constraintSet.addUndConstraint(fieldCons); constraintSet.addUndConstraint(recvCons); diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 7441a159..d58b468d 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -930,6 +930,16 @@ public class TestComplete { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "PatternMatchingListAppend.jav"); var clazz = classFiles.get("PatternMatchingListAppend"); 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