Skip to content

Commit

Permalink
Fixes for type inference
Browse files Browse the repository at this point in the history
  • Loading branch information
xdrop committed Mar 10, 2017
1 parent 5ea0249 commit acdac67
Show file tree
Hide file tree
Showing 17 changed files with 330 additions and 86 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -370,8 +370,13 @@ public Type visit(LambdaExpr node, Boolean solveLambdas) {
ExpressionStmt expressionStmt = (ExpressionStmt) lambdaExpr.getBody(); ExpressionStmt expressionStmt = (ExpressionStmt) lambdaExpr.getBody();
Type actualType = facade.getType(expressionStmt.getExpression()); Type actualType = facade.getType(expressionStmt.getExpression());
Type formalType = functionalMethod.get().returnType(); Type formalType = functionalMethod.get().returnType();
inferenceContext.addPair(formalType, actualType);
result = inferenceContext.resolve(inferenceContext.addSingle(result)); // if the functional method returns void anyway
// we don't need to bother inferring types
if (!(formalType instanceof VoidType)){
inferenceContext.addPair(formalType, actualType);
result = inferenceContext.resolve(inferenceContext.addSingle(result));
}
} else { } else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
Expand All @@ -398,7 +403,8 @@ public Type visit(MethodReferenceExpr node, Boolean solveLambdas) {
logger.finest("getType on method reference expr " + refMethod.getCorrespondingDeclaration().getName()); logger.finest("getType on method reference expr " + refMethod.getCorrespondingDeclaration().getName());
//logger.finest("Method param " + refMethod.getCorrespondingDeclaration().getParam(pos)); //logger.finest("Method param " + refMethod.getCorrespondingDeclaration().getParam(pos));
if (solveLambdas) { if (solveLambdas) {
Type result = refMethod.getCorrespondingDeclaration().getParam(pos).getType(); MethodUsage usage = facade.solveMethodAsUsage(callExpr);
Type result = usage.getParamType(pos);
// We need to replace the type variables // We need to replace the type variables
Context ctx = JavaParserFactory.getContext(node, typeSolver); Context ctx = JavaParserFactory.getContext(node, typeSolver);
result = facade.solveGenericTypes(result, ctx, typeSolver); result = facade.solveGenericTypes(result, ctx, typeSolver);
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar
String importString = importDecl.getNameAsString(); String importString = importDecl.getNameAsString();


com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration ref = typeSolver.solveType(importString); com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration ref = typeSolver.solveType(importString);
SymbolReference<MethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, typeSolver, true); SymbolReference<MethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver);


if (method.isSolved()) { if (method.isSolved()) {
return method; return method;
Expand All @@ -225,7 +225,7 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar
if (qName.equals(name) || qName.endsWith("." + name)) { if (qName.equals(name) || qName.endsWith("." + name)) {
String typeName = getType(qName); String typeName = getType(qName);
com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration ref = typeSolver.solveType(typeName); com.github.javaparser.symbolsolver.model.declarations.TypeDeclaration ref = typeSolver.solveType(typeName);
SymbolReference<MethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, typeSolver, true); SymbolReference<MethodDeclaration> method = MethodResolutionLogic.solveMethodInType(ref, name, argumentsTypes, true, typeSolver);
if (method.isSolved()) { if (method.isSolved()) {
return method; return method;
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar
if (!Object.class.getCanonicalName().equals(typeDeclaration.getQualifiedName())) { if (!Object.class.getCanonicalName().equals(typeDeclaration.getQualifiedName())) {
for (ReferenceType ancestor : typeDeclaration.getAncestors()) { for (ReferenceType ancestor : typeDeclaration.getAncestors()) {
SymbolReference<MethodDeclaration> res = MethodResolutionLogic SymbolReference<MethodDeclaration> res = MethodResolutionLogic
.solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, typeSolver, staticOnly); .solveMethodInType(ancestor.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver);
// consider methods from superclasses and only default methods from interfaces : // consider methods from superclasses and only default methods from interfaces :
// not true, we should keep abstract as a valid candidate // not true, we should keep abstract as a valid candidate
// abstract are removed in MethodResolutionLogic.isApplicable is necessary // abstract are removed in MethodResolutionLogic.isApplicable is necessary
Expand All @@ -108,7 +108,7 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar


// if is interface and candidate method list is empty, we should check the Object Methods // if is interface and candidate method list is empty, we should check the Object Methods
if (candidateMethods.isEmpty() && typeDeclaration.isInterface()) { if (candidateMethods.isEmpty() && typeDeclaration.isInterface()) {
SymbolReference<MethodDeclaration> res = MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, typeSolver, false); SymbolReference<MethodDeclaration> res = MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver);
if (res.isSolved()) { if (res.isSolved()) {
candidateMethods.add(res.getCorrespondingDeclaration()); candidateMethods.add(res.getCorrespondingDeclaration());
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.model.resolution.Value; import com.github.javaparser.symbolsolver.model.resolution.Value;
import com.github.javaparser.symbolsolver.model.typesystem.LambdaConstraintType;
import com.github.javaparser.symbolsolver.model.typesystem.Type; import com.github.javaparser.symbolsolver.model.typesystem.Type;
import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator; import com.github.javaparser.symbolsolver.resolution.SymbolDeclarator;
import javaslang.Tuple2; import javaslang.Tuple2;
Expand Down Expand Up @@ -64,7 +65,14 @@ public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) {
MethodUsage methodUsage = JavaParserFacade.get(typeSolver).solveMethodAsUsage(methodCallExpr); MethodUsage methodUsage = JavaParserFacade.get(typeSolver).solveMethodAsUsage(methodCallExpr);
int i = pos(methodCallExpr, wrappedNode); int i = pos(methodCallExpr, wrappedNode);
Type lambdaType = methodUsage.getParamTypes().get(i); Type lambdaType = methodUsage.getParamTypes().get(i);
Value value = new Value(lambdaType.asReferenceType().typeParametersValues().get(0), name); Type argType = lambdaType.asReferenceType().typeParametersValues().get(0);
LambdaConstraintType conType;
if (argType.isWildcard()){
conType = LambdaConstraintType.bound(argType.asWildcard().getBoundedType());
} else {
conType = LambdaConstraintType.bound(argType);
}
Value value = new Value(conType, name);
return Optional.of(value); return Optional.of(value);
} else if (getParentNode(wrappedNode) instanceof VariableDeclarator) { } else if (getParentNode(wrappedNode) instanceof VariableDeclarator) {
VariableDeclarator variableDeclarator = (VariableDeclarator) getParentNode(wrappedNode); VariableDeclarator variableDeclarator = (VariableDeclarator) getParentNode(wrappedNode);
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public Optional<MethodUsage> solveMethodAsUsage(String name, List<Type> argument
String className = ((NameExpr) scope).getName().getId(); String className = ((NameExpr) scope).getName().getId();
SymbolReference<TypeDeclaration> ref = solveType(className, typeSolver); SymbolReference<TypeDeclaration> ref = solveType(className, typeSolver);
if (ref.isSolved()) { if (ref.isSolved()) {
SymbolReference<MethodDeclaration> m = MethodResolutionLogic.solveMethodInType(ref.getCorrespondingDeclaration(), name, argumentsTypes, typeSolver, false); SymbolReference<MethodDeclaration> m = MethodResolutionLogic.solveMethodInType(ref.getCorrespondingDeclaration(), name, argumentsTypes, typeSolver);
if (m.isSolved()) { if (m.isSolved()) {
MethodUsage methodUsage = new MethodUsage(m.getCorrespondingDeclaration()); MethodUsage methodUsage = new MethodUsage(m.getCorrespondingDeclaration());
methodUsage = resolveMethodTypeParameters(methodUsage, argumentsTypes); methodUsage = resolveMethodTypeParameters(methodUsage, argumentsTypes);
Expand Down Expand Up @@ -140,7 +140,7 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar
SymbolReference<TypeDeclaration> symbolReference = this.solveType(scopeAsName.getName().getId(), typeSolver); SymbolReference<TypeDeclaration> symbolReference = this.solveType(scopeAsName.getName().getId(), typeSolver);
if (symbolReference.isSolved() && symbolReference.getCorrespondingDeclaration().isType()) { if (symbolReference.isSolved() && symbolReference.getCorrespondingDeclaration().isType()) {
TypeDeclaration typeDeclaration = symbolReference.getCorrespondingDeclaration().asType(); TypeDeclaration typeDeclaration = symbolReference.getCorrespondingDeclaration().asType();
return MethodResolutionLogic.solveMethodInType(typeDeclaration, name, argumentsTypes, typeSolver, false); return MethodResolutionLogic.solveMethodInType(typeDeclaration, name, argumentsTypes, false, typeSolver);
} }
} }


Expand All @@ -152,27 +152,29 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar
} }
if (typeOfScope.isWildcard()) { if (typeOfScope.isWildcard()) {
if (typeOfScope.asWildcard().isExtends() || typeOfScope.asWildcard().isSuper()) { if (typeOfScope.asWildcard().isExtends() || typeOfScope.asWildcard().isSuper()) {
return MethodResolutionLogic.solveMethodInType(typeOfScope.asWildcard().getBoundedType().asReferenceType().getTypeDeclaration(), name, argumentsTypes, typeSolver, false); return MethodResolutionLogic.solveMethodInType(typeOfScope.asWildcard().getBoundedType().asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
} else { } else {
return MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, typeSolver, false); return MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver);
} }
} else if (typeOfScope.isArray()) { } else if (typeOfScope.isArray()) {
// method call on array are Object methods // method call on array are Object methods
return MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, typeSolver, false); return MethodResolutionLogic.solveMethodInType(new ReflectionClassDeclaration(Object.class, typeSolver), name, argumentsTypes, false, typeSolver);
} else if (typeOfScope.isTypeVariable()) { } else if (typeOfScope.isTypeVariable()) {
for (TypeParameterDeclaration.Bound bound : typeOfScope.asTypeParameter().getBounds(typeSolver)) { for (TypeParameterDeclaration.Bound bound : typeOfScope.asTypeParameter().getBounds(typeSolver)) {
SymbolReference<MethodDeclaration> res = MethodResolutionLogic.solveMethodInType(bound.getType().asReferenceType().getTypeDeclaration(), name, argumentsTypes, typeSolver, false); SymbolReference<MethodDeclaration> res = MethodResolutionLogic.solveMethodInType(bound.getType().asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
if (res.isSolved()) { if (res.isSolved()) {
return res; return res;
} }
} }
return SymbolReference.unsolved(MethodDeclaration.class); return SymbolReference.unsolved(MethodDeclaration.class);
} else if (typeOfScope.isConstraint()){
return MethodResolutionLogic.solveMethodInType(typeOfScope.asConstraintType().getBound().asReferenceType().getTypeDeclaration(), name, argumentsTypes, typeSolver);
} else { } else {
return MethodResolutionLogic.solveMethodInType(typeOfScope.asReferenceType().getTypeDeclaration(), name, argumentsTypes, typeSolver, false); return MethodResolutionLogic.solveMethodInType(typeOfScope.asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
} }
} else { } else {
Type typeOfScope = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode); Type typeOfScope = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
return MethodResolutionLogic.solveMethodInType(typeOfScope.asReferenceType().getTypeDeclaration(), name, argumentsTypes, typeSolver, false); return MethodResolutionLogic.solveMethodInType(typeOfScope.asReferenceType().getTypeDeclaration(), name, argumentsTypes, false, typeSolver);
} }
} }


Expand Down Expand Up @@ -260,11 +262,36 @@ private void inferTypes(Type source, Type target, Map<TypeParameterDeclaration,
return; return;
} }
if (source.isWildcard() && target.isTypeVariable()) { if (source.isWildcard() && target.isTypeVariable()) {
if (source.asWildcard().isBounded()) { mappings.put(target.asTypeParameter(), source);
return;
}
if (source.isArray() && target.isWildcard()){
if(target.asWildcard().isBounded()){
inferTypes(source, target.asWildcard().getBoundedType(), mappings);
return;
}
return;
}
if (source.isArray() && target.isTypeVariable()) {
mappings.put(target.asTypeParameter(), source);
return;
}

if (source.isWildcard() && target.isReferenceType()){
if (source.asWildcard().isBounded()){
inferTypes(source.asWildcard().getBoundedType(), target, mappings); inferTypes(source.asWildcard().getBoundedType(), target, mappings);
} }
return; return;
} }
if (source.isConstraint() && target.isReferenceType()){
inferTypes(source.asConstraintType().getBound(), target, mappings);
return;
}

if (source.isConstraint() && target.isTypeVariable()){
inferTypes(source.asConstraintType().getBound(), target, mappings);
return;
}
if (source.isTypeVariable() && target.isTypeVariable()) { if (source.isTypeVariable() && target.isTypeVariable()) {
mappings.put(target.asTypeParameter(), source); mappings.put(target.asTypeParameter(), source);
return; return;
Expand Down Expand Up @@ -362,6 +389,9 @@ private Optional<MethodUsage> solveMethodAsUsage(Type type, String name, List<Ty
} else { } else {
throw new UnsupportedOperationException("unbounded wildcard"); throw new UnsupportedOperationException("unbounded wildcard");
} }
} else if (type instanceof LambdaConstraintType){
LambdaConstraintType constraintType = (LambdaConstraintType) type;
return solveMethodAsUsage(constraintType.getBound(), name, argumentsTypes, typeSolver, invokationContext);
} else if (type instanceof ArrayType) { } else if (type instanceof ArrayType) {
// An array inherits methods from Object not from it's component type // An array inherits methods from Object not from it's component type
return solveMethodAsUsage(new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver), name, argumentsTypes, typeSolver, invokationContext); return solveMethodAsUsage(new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver), name, argumentsTypes, typeSolver, invokationContext);
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ public boolean isAssignableBy(Type other) {
} else if (other.isTypeVariable()) { } else if (other.isTypeVariable()) {
// TODO look bounds... // TODO look bounds...
return true; return true;
} else if (other.isConstraint()){
return isAssignableBy(other.asConstraintType().getBound());
} else if (other.isWildcard()) { } else if (other.isWildcard()) {
if (this.getQualifiedName().equals(Object.class.getCanonicalName())) { if (this.getQualifiedName().equals(Object.class.getCanonicalName())) {
return true; return true;
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> ar
} }
if (getSuperClass() != null) { if (getSuperClass() != null) {
ClassDeclaration superClass = (ClassDeclaration) getSuperClass().getTypeDeclaration(); ClassDeclaration superClass = (ClassDeclaration) getSuperClass().getTypeDeclaration();
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(superClass, name, argumentsTypes, typeSolver, false); SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(superClass, name, argumentsTypes, staticOnly, typeSolver);
if (ref.isSolved()) { if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration()); methods.add(ref.getCorrespondingDeclaration());
} }
} }
for (ReferenceType interfaceDeclaration : getInterfaces()) { for (ReferenceType interfaceDeclaration : getInterfaces()) {
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(interfaceDeclaration.getTypeDeclaration(), name, argumentsTypes, typeSolver, false); SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(interfaceDeclaration.getTypeDeclaration(), name, argumentsTypes, staticOnly, typeSolver);
if (ref.isSolved()) { if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration()); methods.add(ref.getCorrespondingDeclaration());
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -89,12 +89,27 @@ public SymbolReference<MethodDeclaration> solveMethod(String name, List<Type> pa
MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver); MethodDeclaration methodDeclaration = new ReflectionMethodDeclaration(method, typeSolver);
methods.add(methodDeclaration); methods.add(methodDeclaration);
} }

for (ReferenceType ancestor : getAncestors()) {
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(ancestor.getTypeDeclaration(), name, parameterTypes, staticOnly, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
}
}

if (getAncestors().isEmpty()){
ReferenceTypeImpl objectClass = new ReferenceTypeImpl(new ReflectionClassDeclaration(Object.class, typeSolver), typeSolver);
SymbolReference<MethodDeclaration> ref = MethodResolutionLogic.solveMethodInType(objectClass.getTypeDeclaration(), name, parameterTypes, staticOnly, typeSolver);
if (ref.isSolved()) {
methods.add(ref.getCorrespondingDeclaration());
}
}
return MethodResolutionLogic.findMostApplicable(methods, name, parameterTypes, typeSolver); return MethodResolutionLogic.findMostApplicable(methods, name, parameterTypes, typeSolver);
} }


@Override @Override
public String toString() { public String toString() {
return "ReflectionClassDeclaration{" + return "ReflectionInterfaceDeclaration{" +
"clazz=" + clazz.getCanonicalName() + "clazz=" + clazz.getCanonicalName() +
'}'; '}';
} }
Expand Down
Loading

0 comments on commit acdac67

Please sign in to comment.