diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java index 2bf82cd7..f219c196 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/FCGenerator.java @@ -34,11 +34,12 @@ public class FCGenerator { //PL 2018-09-18: gtvs vor die for-Schleife gezogen, damit immer die gleichen Typeplaceholder eingesetzt werden. HashMap gtvs = new HashMap<>(); for(ClassOrInterface cly : availableClasses){ - pairs.addAll(getSuperTypes(cly, availableClasses, gtvs, classLoader)); + List newPairs = getSuperTypes(cly, availableClasses, gtvs, classLoader); + pairs.addAll(newPairs); //For all Functional Interfaces FI: FunN$$<... args auf dem Functional Interface ...> <. FI is added to FC if (isFunctionalInterface(cly)) { - pairs.add(genImplFunType(cly)); + pairs.add(genImplFunType(cly, newPairs.get(0).TA1, gtvs)); } } return pairs; @@ -46,17 +47,22 @@ public class FCGenerator { private static Boolean isFunctionalInterface(ClassOrInterface cly) { - return (cly.isInterface() && cly.getMethods().size() == 1); + return (cly.isInterface() && (cly.isFunctionalInterface() || cly.getMethods().size() == 1)); } - private static Pair genImplFunType(ClassOrInterface cly) { - Method m = cly.getMethods().get(0); - List tl = - (m.getParameterList().getFormalparalist().stream().map(p -> p.getType()).collect(Collectors.toList())); - tl.add(m.getReturnType()); - return new Pair(new RefType(new JavaClassName("Fun" + (tl.size()-1) + "$$"), tl, new NullToken()), - new RefType(cly.getClassName(), new NullToken())); - // new FunN(lambdaParams), + private static Pair genImplFunType(ClassOrInterface cly, RefTypeOrTPHOrWildcardOrGeneric fIType, HashMap gtvs) { + for(Method m : cly.getMethods()) { + if (!java.lang.reflect.Modifier.isAbstract(m.modifier)) + continue; + List tl = + (m.getParameterList().getFormalparalist() + .stream().map(p -> p.getType().acceptTV(new TypeExchanger(gtvs))) + .collect(Collectors.toList())); + tl.add(m.getReturnType().acceptTV(new TypeExchanger(gtvs))); + return new Pair(new RefType(new JavaClassName("Fun" + (tl.size()-1) + "$$"), tl, new NullToken()), + fIType); + } + return null; //kann nicht passieren, da die Methode nur aufgerufen wird wenn cl Functional Interface ist } diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java index 95dfec33..0a7106f3 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/SyntaxTreeGenerator.java @@ -210,6 +210,7 @@ public class SyntaxTreeGenerator { List methods = new ArrayList<>(); List constructors = new ArrayList<>(); Boolean isInterface = false; + Boolean isFunctionalInterface = false; List implementedInterfaces = new ArrayList<>(); List permittedSubtypes = new ArrayList<>(); for (ClassBodyDeclarationContext clsbodydecl : ctx.classBody().classBodyDeclaration()) { @@ -233,7 +234,7 @@ public class SyntaxTreeGenerator { } var ctor = Optional.of(this.generatePseudoConstructor(ctx.identifier().getText(), fieldInitializations, genericClassParameters, offset)); var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericClassParameters, offset)); - return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); + return new ClassOrInterface(modifiers, name, fielddecl, ctor, staticCtor, methods, constructors, genericClassParameters, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset); } @@ -408,7 +409,7 @@ public class SyntaxTreeGenerator { } var staticCtor = Optional.of(this.generateStaticConstructor(ctx.identifier().getText(), staticFieldInitializations, genericParams, ctx.getStart())); - return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, extendedInterfaces, permittedSubtypes, ctx.getStart()); + return new ClassOrInterface(modifiers, name, fields, Optional.empty(), staticCtor, methods, new ArrayList<>(), genericParams, superClass, true, methods.size() == 1 ? true : false, extendedInterfaces, permittedSubtypes, ctx.getStart()); } private GenericDeclarationList createEmptyGenericDeclarationList(Token classNameIdentifier) { diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java b/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java index fa319e49..a4c527a0 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/ClassOrInterface.java @@ -28,11 +28,12 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { private GenericDeclarationList genericClassParameters; private RefType superClass; protected boolean isInterface; + protected boolean isFunctionalInterface; private List implementedInterfaces; private List permittedSubtypes; private List constructors; - public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, List permittedSubtypes, Token offset) { + public ClassOrInterface(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, Boolean isFunctionalInterface, List implementedInterfaces, List permittedSubtypes, Token offset) { super(offset); if (isInterface) { modifiers |= Modifier.INTERFACE | Modifier.ABSTRACT; @@ -45,6 +46,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { this.genericClassParameters = genericClassParameters; this.superClass = superClass; this.isInterface = isInterface; + this.isFunctionalInterface= isFunctionalInterface; this.implementedInterfaces = implementedInterfaces; this.permittedSubtypes = permittedSubtypes; this.methods = methods; @@ -64,6 +66,7 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { this.genericClassParameters = cl.genericClassParameters; this.superClass = cl.superClass; this.isInterface = cl.isInterface; + this.isFunctionalInterface= cl.isFunctionalInterface; this.implementedInterfaces = cl.implementedInterfaces; this.methods = new ArrayList<>(cl.methods); this.constructors = new ArrayList<>(cl.constructors); @@ -82,6 +85,10 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { return (Modifier.INTERFACE & this.getModifiers()) != 0; } + public boolean isFunctionalInterface() { + return this.isFunctionalInterface; + } + // Gets if it is added public Boolean areMethodsAdded() { return methodAdded; @@ -173,4 +180,5 @@ public class ClassOrInterface extends SyntaxTreeNode implements TypeScope { public String toString() { return this.name.toString() + this.genericClassParameters.toString(); } + } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java b/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java index 462c5c79..ee93f32e 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/Record.java @@ -14,6 +14,6 @@ import javax.swing.text.html.Option; public class Record extends ClassOrInterface { public Record(int modifiers, JavaClassName name, List fielddecl, Optional fieldInitializations, Optional staticInitializer, List methods, List constructors, GenericDeclarationList genericClassParameters, RefType superClass, Boolean isInterface, List implementedInterfaces, Token offset) { - super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, implementedInterfaces, new ArrayList<>(), offset); + super(modifiers, name, fielddecl, fieldInitializations, staticInitializer, methods, constructors, genericClassParameters, superClass, isInterface, methods.size() == 1 ? true : false, implementedInterfaces, new ArrayList<>(), offset); } } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java index 09d72fe8..86187ee6 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java @@ -1,6 +1,7 @@ package de.dhbwstuttgart.syntaxtree.factory; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.reflect.*; import java.lang.reflect.Constructor; import java.lang.reflect.Type; @@ -86,7 +87,6 @@ public class ASTFactory { } catch (IOException e) { // Skip } - JavaClassName name = new JavaClassName(jreClass.getName()); List methoden = new ArrayList<>(); List konstruktoren = new ArrayList<>(); @@ -112,6 +112,12 @@ public class ASTFactory { } int modifier = jreClass.getModifiers(); boolean isInterface = jreClass.isInterface(); + List aLA; + boolean isFunctionalInterface = + (aLA = Arrays.asList(jreClass.getAnnotations())).size() > 0 && + aLA.get(0) instanceof FunctionalInterface ? + true : + false; // see: https://stackoverflow.com/questions/9934774/getting-generic-parameter-from-supertype-class ParameterizedType parameterSuperClass = null; Type tempSuperClass = jreClass.getGenericSuperclass(); @@ -141,7 +147,7 @@ public class ASTFactory { Token offset = new NullToken(); // Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde - var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, implementedInterfaces, permittedSubtypes, offset); + var cinf = new ClassOrInterface(modifier, name, felder, Optional.empty() /* eingefuegt PL 2018-11-24 */, Optional.empty(), methoden, konstruktoren, genericDeclarationList, superClass, isInterface, isFunctionalInterface, implementedInterfaces, permittedSubtypes, offset); cache.put(jreClass, cinf); return cinf; } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java index 48a07459..8cfb2e8e 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/assumptions/FunNClass.java @@ -22,7 +22,7 @@ import java.util.Optional; public class FunNClass extends ClassOrInterface { public FunNClass(List funNParams) { - super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, new ArrayList<>(), new ArrayList<>(), new NullToken()); + super(0, new JavaClassName("Fun" + (funNParams.size() - 1)), new ArrayList<>(), Optional.empty(), Optional.empty() /* eingefuegt PL 2018-11-24 */, createMethods(funNParams), new ArrayList<>(), createGenerics(funNParams), ASTFactory.createObjectType(), true, false, new ArrayList<>(), new ArrayList<>(), new NullToken()); } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java b/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java index 006502ac..39b0de33 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java @@ -890,26 +890,39 @@ public class RuleSet implements IRuleSet{ if(!(lhsType instanceof FunNType)) return Optional.empty(); - //FunN$$<...> <. FunctinalInterface wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...> + //FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...> if (rhsType instanceof ReferenceType) { - UnifyType typeD = pair.getRhsType(); + UnifyType typeFI = pair.getRhsType(); - Optional opt = fc.getRightHandedNoParameterType(typeD.getName()); + Optional opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName()); if(!opt.isPresent()) return Optional.empty(); - // Should be eual as typeD - UnifyType typeFunFc = opt.get(); + // The generic Version of typeFI (FI) + UnifyType typeDgen = opt.get(); + // Actually greater+ because the types are ensured to have different names + Set smaller = fc.getChildren(typeDgen); + opt = smaller.stream().filter(x -> x.getName().equals(pair.getLhsType().getName())).findAny(); - if(!(typeFunFc instanceof FunNType)) + if(!opt.isPresent()) return Optional.empty(); + TypeParams typeDParams = typeFI.getTypeParams(); + TypeParams typeDgenParams = typeDgen.getTypeParams(); + + Unifier unif = Unifier.identity(); + for(int i = 0; i < typeDParams.size(); i++) { + if (typeDgenParams.get(i) instanceof PlaceholderType) + unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); + else System.out.println("ERROR"); + } + UnifyType newRhsType = opt.get(); Set result = new HashSet<>(); - result.add(new UnifyPair(lhsType, newRhsType, PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); + result.add(new UnifyPair(lhsType, unif.apply(newRhsType), PairOperator.SMALLERDOT, pair.getSubstitution(), pair.getBasePair())); return Optional.of(result); } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java b/src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java index b3704c10..557b664a 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java @@ -60,7 +60,7 @@ public interface IFiniteClosure { public Set smArg(FunNType type, Set fBounded); public Optional getLeftHandedType(String typeName); - public Optional getRightHandedNoParameterType(String typeName); + public Optional getRightHandedFunctionalInterfaceType(String typeName); public Set getAncestors(UnifyType t); public Set getChildren(UnifyType t); public Set getAllTypesByName(String typeName); diff --git a/src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java b/src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java index bc84ead4..55340fdc 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java @@ -609,13 +609,13 @@ implements IFiniteClosure { } @Override - public Optional getRightHandedNoParameterType(String typeName) { + public Optional getRightHandedFunctionalInterfaceType(String typeName) { if(!strInheritanceGraph.containsKey(typeName)) return Optional.empty(); for(UnifyPair pair : pairs) - if(pair.getRhsType().getName().equals(typeName) && pair.getRhsType().typeParams.size() == 0) - return Optional.of(pair.getLhsType()); + if(pair.getRhsType().getName().equals(typeName)) + return Optional.of(pair.getRhsType()); return Optional.empty(); } diff --git a/src/test/java/targetast/ASTToTypedTargetAST.java b/src/test/java/targetast/ASTToTypedTargetAST.java index e3eb2276..b1389f0f 100644 --- a/src/test/java/targetast/ASTToTypedTargetAST.java +++ b/src/test/java/targetast/ASTToTypedTargetAST.java @@ -22,7 +22,7 @@ public class ASTToTypedTargetAST { @Test public void emptyClass() { - ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, new ArrayList<>(), new ArrayList<>(), new NullToken()); + ClassOrInterface emptyClass = new ClassOrInterface(0, new JavaClassName("EmptyClass"), new ArrayList<>(), Optional.empty(), Optional.empty(), new ArrayList<>(), new ArrayList<>(), new GenericDeclarationList(new ArrayList<>(), new NullToken()), new RefType(new JavaClassName("Object"), new NullToken()), false, false, new ArrayList<>(), new ArrayList<>(), new NullToken()); ResultSet emptyResultSet = new ResultSet(new HashSet<>()); TargetStructure emptyTargetClass = new ASTToTargetAST(List.of(emptyResultSet)).convert(emptyClass); assert emptyTargetClass.getName().equals("EmptyClass");