Start implementing family of generics

This commit is contained in:
Victorious3 2022-06-22 17:06:49 +02:00
parent 3b439a49cd
commit f00ee2598f
15 changed files with 452 additions and 55 deletions

View File

@ -15,6 +15,7 @@ import java.lang.invoke.MethodType;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Opcodes.*;
import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*; import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*;
@ -527,7 +528,7 @@ public class Codegen {
var mv = state.mv; var mv = state.mv;
var name = "lambda$" + state.lambdaCounter; var name = "lambda$" + state.lambdaCounter;
var impl = new TargetMethod( var impl = new TargetMethod(
ACC_PRIVATE, new TargetRefType(clazz.qualifiedName()), name, ACC_PRIVATE, name, Set.of(),
lambda.params(), lambda.returnType(), lambda.block() lambda.params(), lambda.returnType(), lambda.block()
); );
generateMethod(impl); generateMethod(impl);

View File

@ -1,9 +1,8 @@
package de.dhbwstuttgart.target.generate; package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.Block; import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.tree.*; import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.TargetBlock; import de.dhbwstuttgart.target.tree.expression.TargetBlock;
@ -11,53 +10,247 @@ import de.dhbwstuttgart.target.tree.expression.TargetExpression;
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.Stream;
public class ASTToTargetAST { public class ASTToTargetAST {
protected List<HashMap<TypePlaceholder, TargetType>> all; protected List<Sigma> all;
protected HashMap<TypePlaceholder, TargetType> sigma; protected Sigma sigma;
private class ResultPairV implements ResultPairVisitor { private class Sigma {
HashMap<Method, Set<TargetGeneric>> computedGenerics = new HashMap<>();
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
Map<TypePlaceholder, TargetType> result = new HashMap<>();
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
Sigma(ResultSet constraints) {
ASTToTargetAST.this.sigma = this;
Set<List<TypePlaceholder>> equalitySet = new HashSet<>();
Map<TypePlaceholder, List<TypePlaceholder>> unified = new HashMap<>();
for (var constraint : constraints.results) {
if (constraint instanceof PairTPHEqualTPH p) {
if (unified.containsKey(p.getLeft())) {
var equals = unified.get(p.getLeft());
equals.add(p.getRight());
unified.put(p.getLeft(), equals);
} else if (unified.containsKey(p.getRight())) {
var equals = unified.get(p.getRight());
equals.add(p.getLeft());
unified.put(p.getRight(), equals);
} else {
List<TypePlaceholder> equals = new ArrayList<>();
equals.add(p.getLeft());
equals.add(p.getRight());
unified.put(p.getLeft(), equals);
unified.put(p.getRight(), equals);
equalitySet.add(equals);
}
}
}
for (var constraint : constraints.results) {
if (constraint instanceof PairTPHsmallerTPH p) {
var left = p.left;
var right = p.right;
if (unified.containsKey(left))
left = unified.get(left).get(0);
if (unified.containsKey(right))
right = unified.get(right).get(0);
simplifiedConstraints.add(new PairTPHsmallerTPH(left, right));
result.put(right, new TargetGenericType(right.getName()));
result.put(left, new TargetGenericType(left.getName()));
}
}
System.out.println(simplifiedConstraints);
for (var equality : equalitySet) {
var first = equality.get(0);
for (var i = 1; i < equality.size(); i++)
this.equality.put(equality.get(i), first);
}
for (var constraint : constraints.results) {
if (constraint instanceof PairTPHequalRefTypeOrWildcardType p) {
result.put(p.left, convert(p.right));
}
}
}
// Family of generated Generics
Set<TargetGeneric> generics(ClassOrInterface owner, Method method) {
if (computedGenerics.containsKey(method))
return computedGenerics.get(method);
Set<TargetGeneric> result = new HashSet<>();
computedGenerics.put(method, result);
method.block.accept(new AbstractStatementVisitor() {
// These two methods do the actual work
@Override @Override
public void visit(PairTPHsmallerTPH p) { public void visit(LocalVarDecl localVarDecl) {
throw new NotImplementedException(); // TODO
} }
@Override @Override
public void visit(PairTPHequalRefTypeOrWildcardType p) { public void visit(MethodCall methodCall) {
sigma.put(p.left, convert(p.right)); if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
if (expressionReceiver.expr instanceof This) {
// TODO This is going to fail spectacularly for overloaded methods
var optMethod = owner.getMethods().stream().filter(m -> m.name.equals(methodCall.name)).findFirst();
assert optMethod.isPresent();
var method = optMethod.get();
Set<TargetGeneric> generics = generics(owner, method);
}
}
}
// Everything down here is just for walking the AST
@Override
public void visit(ArgumentList argumentList) {
argumentList.getArguments().forEach(expr -> expr.accept(this));
} }
@Override @Override
public void visit(PairTPHEqualTPH p) { public void visit(LambdaExpression lambdaExpression) {
throw new NotImplementedException(); lambdaExpression.methodBody.accept(this);
}
@Override
public void visit(Assign assign) {
assign.rightSide.accept(this);
}
@Override
public void visit(BinaryExpr binary) {
binary.lexpr.accept(this);
binary.rexpr.accept(this);
}
@Override
public void visit(Block block) {
for (var expr : block.statements)
expr.accept(this);
}
@Override
public void visit(ForStmt forStmt) {
forStmt.body_Loop_block.accept(this);
}
@Override
public void visit(IfStmt ifStmt) {
ifStmt.then_block.accept(this);
ifStmt.else_block.accept(this);
}
@Override
public void visit(NewClass newClass) {
newClass.arglist.accept(this);
}
@Override
public void visit(NewArray newArray) {
newArray.expr.forEach(expr -> expr.accept(this));
}
@Override
public void visit(Return aReturn) {
aReturn.retexpr.accept(this);
}
@Override
public void visit(WhileStmt whileStmt) {
whileStmt.loopBlock.accept(this);
}
@Override
public void visit(DoStmt whileStmt) {
whileStmt.loopBlock.accept(this);
}
@Override
public void visit(UnaryExpr unaryExpr) {
unaryExpr.expr.accept(this);
}
});
return result;
}
void findAllBounds(String name, Set<TargetGeneric> generics) {
for (var rsp : simplifiedConstraints) {
var left = equality.getOrDefault(rsp.left, rsp.left);
var right = equality.getOrDefault(rsp.right, rsp.right);
if (left.getName().equals(name)) {
generics.add(new TargetGeneric(name, new TargetGenericType(right.getName())));
findAllBounds(right.getName(), generics);
return;
}
}
generics.add(new TargetGeneric(name, TargetType.Object));
}
Set<TargetGeneric> findAllBounds(TargetGenericType type) {
Set<TargetGeneric> result = new HashSet<>();
findAllBounds(type.name(), result);
return result;
}
Set<TargetGeneric> generics(ClassOrInterface classOrInterface) {
Set<TargetGeneric> result = new HashSet<>();
for (var field : classOrInterface.getFieldDecl()) {
if (field.getType() instanceof TypePlaceholder tph) {
var tpe = get(tph);
switch (tpe) {
case TargetSpecializedType specializedType:
specializedType.params().stream().flatMap(targetType -> {
if (targetType instanceof TargetSpecializedType spc)
return Stream.concat(Stream.of(targetType), spc.params().stream());
return Stream.of(targetType);
}).forEach(param -> {
if (param instanceof TargetGenericType genericType) {
result.addAll(findAllBounds(genericType));
}
});
break;
case TargetGenericType genericType:
result.addAll(findAllBounds(genericType));
default: break;
}
}
}
return result;
}
TargetType get(TypePlaceholder tph) {
if (equality.containsKey(tph)) {
return get(equality.get(tph));
}
return result.get(tph);
} }
} }
public ASTToTargetAST(List<ResultSet> resultSets) { public ASTToTargetAST(List<ResultSet> resultSets) {
all = new ArrayList<>(); all = new ArrayList<>();
for (var set : resultSets) { for (var set : resultSets) {
this.sigma = new HashMap<>(); all.add(new Sigma(set));
for (var pair : set.results) {
var visitor = new ResultPairV();
pair.accept(visitor);
} }
all.add(this.sigma);
}
this.sigma = all.get(0); this.sigma = all.get(0);
} }
public TargetClass convert(ClassOrInterface input) { public TargetClass convert(ClassOrInterface input) {
return new TargetClass(input.getModifiers(),input.getClassName().toString(), convert(input.getSuperClass()), return new TargetClass(input.getModifiers(),input.getClassName().toString(), convert(input.getSuperClass()),
input.getSuperInterfaces().stream().map(it -> sigma.get(it)).toList(), sigma.generics(input),
input.getConstructors().stream().map(it -> convert(input, it)).flatMap(List::stream).toList(), input.getSuperInterfaces().stream().map(this::convert).toList(),
input.getFieldDecl().stream().map(it -> convert(input, it)).toList(), input.getConstructors().stream().map(constructor -> this.convert(input, constructor)).flatMap(List::stream).toList(),
input.getMethods().stream().map(it -> convert(input, it)).flatMap(List::stream).toList() input.getFieldDecl().stream().map(this::convert).toList(),
input.getMethods().stream().map(method -> this.convert(input, method)).flatMap(List::stream).toList()
); );
} }
@ -75,7 +268,7 @@ public class ASTToTargetAST {
sigma = s; sigma = s;
List<MethodParameter> params = convert(input.getParameterList()); List<MethodParameter> params = convert(input.getParameterList());
if (parameterSet.stream().noneMatch(p -> p.equals(params))) { if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetConstructor(input.modifier, new TargetRefType(owner.getClassName().getClassName()), params, convert(input.block))); result.add(new TargetConstructor(input.modifier, sigma.generics(owner, input), params, convert(input.block)));
parameterSet.add(params); parameterSet.add(params);
} }
} }
@ -94,8 +287,7 @@ public class ASTToTargetAST {
if (parameterSet.stream().noneMatch(p -> p.equals(params))) { if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetMethod( result.add(new TargetMethod(
input.modifier, input.modifier,
new TargetRefType(owner.getClassName().getClassName()), input.name, sigma.generics(owner, input), params,
input.name, params,
convert(input.getReturnType()), convert(input.getReturnType()),
convert(input.block) convert(input.block)
)); ));
@ -116,10 +308,9 @@ public class ASTToTargetAST {
return converter.result; return converter.result;
} }
private TargetField convert(ClassOrInterface owner, Field input) { private TargetField convert(Field input) {
return new TargetField( return new TargetField(
input.modifier, input.modifier,
new TargetRefType(owner.getClassName().getClassName()),
convert(input.getType()), convert(input.getType()),
input.getName() input.getName()
); );
@ -131,8 +322,11 @@ public class ASTToTargetAST {
public TargetType visit(RefType refType) { public TargetType visit(RefType refType) {
var name = refType.getName().toString(); var name = refType.getName().toString();
if (name.equals("void")) return null; if (name.equals("void")) return null;
return new TargetRefType(name,
refType.getParaList().stream().map(ASTToTargetAST.this::convert).toList()); var params = refType.getParaList().stream().map(ASTToTargetAST.this::convert).toList();
if (name.matches("Fun\\d\\$\\$")) // TODO This seems like a bad idea
return new TargetFunNType(params.size(), params);
return new TargetRefType(name, params);
} }
@Override @Override

View File

@ -0,0 +1,152 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.*;
public abstract class AbstractStatementVisitor implements StatementVisitor {
@Override
public void visit(ArgumentList argumentList) {
}
@Override
public void visit(LambdaExpression lambdaExpression) {
}
@Override
public void visit(Assign assign) {
}
@Override
public void visit(BinaryExpr binary) {
}
@Override
public void visit(Block block) {
}
@Override
public void visit(CastExpr castExpr) {
}
@Override
public void visit(EmptyStmt emptyStmt) {
}
@Override
public void visit(FieldVar fieldVar) {
}
@Override
public void visit(ForStmt forStmt) {
}
@Override
public void visit(IfStmt ifStmt) {
}
@Override
public void visit(InstanceOf instanceOf) {
}
@Override
public void visit(LocalVar localVar) {
}
@Override
public void visit(LocalVarDecl localVarDecl) {
}
@Override
public void visit(MethodCall methodCall) {
}
@Override
public void visit(NewClass methodCall) {
}
@Override
public void visit(NewArray newArray) {
}
@Override
public void visit(Return aReturn) {
}
@Override
public void visit(ReturnVoid aReturn) {
}
@Override
public void visit(StaticClassName staticClassName) {
}
@Override
public void visit(Super aSuper) {
}
@Override
public void visit(This aThis) {
}
@Override
public void visit(WhileStmt whileStmt) {
}
@Override
public void visit(DoStmt whileStmt) {
}
@Override
public void visit(AssignToField assignLeftSide) {
}
@Override
public void visit(AssignToLocal assignLeftSide) {
}
@Override
public void visit(SuperCall superCall) {
}
@Override
public void visit(ExpressionReceiver expressionReceiver) {
}
@Override
public void visit(UnaryExpr unaryExpr) {
}
@Override
public void visit(Literal literal) {
}
}

View File

@ -6,31 +6,42 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, List<TargetType> implementingInterfaces, public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, List<TargetType> implementingInterfaces,
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) { List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
public TargetClass(int modifiers, String qualifiedName) { public TargetClass(int modifiers, String qualifiedName) {
this(modifiers, qualifiedName, TargetType.Object, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
} }
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) { public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
this(modifiers, qualifiedName, TargetType.Object, implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
} }
public String getName() { public String getName() {
return qualifiedName.replaceAll("\\.", "/"); return qualifiedName.replaceAll("\\.", "/");
} }
public void addMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
this.methods.add(new TargetMethod(access, name, generics, parameterTypes, returnType, block));
}
public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) { public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
this.methods.add(new TargetMethod(access, new TargetRefType(this.qualifiedName, List.of()), name, parameterTypes, returnType, block)); addMethod(access, name, Set.of(), parameterTypes, returnType, block);
}
public void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
this.constructors.add(new TargetConstructor(access, generics, paramterTypes, block));
} }
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) { public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
this.constructors.add(new TargetConstructor(access, new TargetRefType(this.qualifiedName, List.of()), paramterTypes, block)); addConstructor(access, Set.of(), paramterTypes, block);
} }
public void addField(int access, TargetRefType type, String name) { public void addField(int access, TargetRefType type, String name) {
this.fields.add(new TargetField(access, new TargetRefType(this.qualifiedName, List.of()), type, name)); this.fields.add(new TargetField(access, type, name));
} }
} }

View File

@ -1,12 +1,12 @@
package de.dhbwstuttgart.target.tree; package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetBlock; import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType; import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List; import java.util.List;
import java.util.Set;
public record TargetConstructor(int access, TargetType owner, List<MethodParameter> parameters, TargetBlock block) { public record TargetConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetBlock block) {
public String getDescriptor() { public String getDescriptor() {
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new)); return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.type.TargetType; import de.dhbwstuttgart.target.tree.type.TargetType;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
public record TargetField(int access, TargetType owner, TargetType type, String name) { public record TargetField(int access, TargetType type, String name) {
public String getDescriptor() { public String getDescriptor() {
return type.toSignature(); return type.toSignature();
} }

View File

@ -0,0 +1,6 @@
package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.type.TargetType;
public record TargetGeneric(String name, TargetType bound) {
}

View File

@ -1,14 +1,13 @@
package de.dhbwstuttgart.target.tree; package de.dhbwstuttgart.target.tree;
import de.dhbwstuttgart.target.tree.expression.TargetBlock; import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType; import de.dhbwstuttgart.target.tree.type.TargetType;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.Set;
public record TargetMethod(int access, TargetType owner, String name, List<MethodParameter> parameters, TargetType returnType, TargetBlock block) { public record TargetMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType, TargetBlock block) {
public static String getDescriptor(TargetType returnType, TargetType... parameters) { public static String getDescriptor(TargetType returnType, TargetType... parameters) {
String ret = "("; String ret = "(";
for (var parameterType : parameters) { for (var parameterType : parameters) {

View File

@ -2,7 +2,7 @@ package de.dhbwstuttgart.target.tree.type;
import java.util.List; import java.util.List;
public record TargetFunNType(int N, List<TargetType> params) implements TargetType { public record TargetFunNType(int N, List<TargetType> params) implements TargetSpecializedType {
@Override @Override
public String getName() { public String getName() {
return "Fun" + N + "$$"; return "Fun" + N + "$$";

View File

@ -7,7 +7,7 @@ public record TargetGenericType(String name) implements TargetType {
} }
@Override @Override
public java.lang.String getName() { public String getName() {
return null; return null;
} }
} }

View File

@ -4,7 +4,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List; import java.util.List;
public record TargetRefType(String name, List<TargetType> params) implements TargetType { public record TargetRefType(String name, List<TargetType> params) implements TargetSpecializedType {
public TargetRefType(String name) { public TargetRefType(String name) {
this(name, List.of()); this(name, List.of());
} }

View File

@ -0,0 +1,7 @@
package de.dhbwstuttgart.target.tree.type;
import java.util.List;
public sealed interface TargetSpecializedType extends TargetType permits TargetFunNType, TargetRefType {
List<TargetType> params();
}

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.tree.type;
import java.util.List; import java.util.List;
public sealed interface TargetType public sealed interface TargetType
permits TargetExtendsWildcard, TargetFunNType, TargetGenericType, TargetRefType, TargetSuperWildcard { permits TargetExtendsWildcard, TargetGenericType, TargetSpecializedType, TargetSuperWildcard {
// Builtin types // Builtin types
TargetRefType Boolean = new TargetRefType("java.lang.Boolean"); TargetRefType Boolean = new TargetRefType("java.lang.Boolean");

View File

@ -38,8 +38,8 @@ public class ASTToTypedTargetAST {
var converter = new ASTToTargetAST(resultSet); var converter = new ASTToTargetAST(resultSet);
var classes = compiler.sourceFiles.get(file).getClasses(); var classes = compiler.sourceFiles.get(file).getClasses();
Class overloading = TestCodegen.generateClass(converter.convert(classes.get(0))); var overloading = TestCodegen.generateClass(converter.convert(classes.get(0)));
Class overloading2 = TestCodegen.generateClass(converter.convert(classes.get(1))); var overloading2 = TestCodegen.generateClass(converter.convert(classes.get(1)));
var test1 = overloading.getDeclaredMethod("test", overloading); var test1 = overloading.getDeclaredMethod("test", overloading);
test1.setAccessible(true); test1.setAccessible(true);
@ -50,4 +50,15 @@ public class ASTToTypedTargetAST {
assertEquals(test1.invoke(overloadingInstance, overloadingInstance), "Overloading"); assertEquals(test1.invoke(overloadingInstance, overloadingInstance), "Overloading");
assertEquals(test2.invoke(overloadingInstance, overloading2Instance), "Overloading2"); assertEquals(test2.invoke(overloadingInstance, overloading2Instance), "Overloading2");
} }
@Test
public void generics() throws Exception {
var file = Path.of(System.getProperty("user.dir"), "/src/test/resources/bytecode/javFiles/TPHsAndGenerics.jav").toFile();
var compiler = new JavaTXCompiler(file);
var resultSet = compiler.typeInference();
var converter = new ASTToTargetAST(resultSet);
var classes = compiler.sourceFiles.get(file).getClasses();
converter.convert(classes.get(0));
}
} }

View File

@ -0,0 +1,16 @@
class TPHsAndGenerics {
id = x -> x;
id2(x) {
return id.apply(x);
}
m(a, b) {
var c = m2(a, b);
return a;
}
m2(a, b) {
return b;
}
}