use of org.eclipse.ceylon.model.typechecker.model.Function in project ceylon by eclipse.
the class AbstractModelLoader method loadFunctionCoercionParameter.
@SuppressWarnings("incomplete-switch")
private Function loadFunctionCoercionParameter(Declaration decl, String paramName, TypeMirror typeMirror, Module moduleScope, Scope scope) {
Function method = new Function();
method.setName(paramName);
method.setUnit(decl.getUnit());
try {
FunctionalInterfaceType functionalInterfaceType = getFunctionalInterfaceType(typeMirror);
MethodMirror functionalMethod = functionalInterfaceType.getMethod();
Type returnType = obtainType(moduleScope, functionalInterfaceType.getReturnType(), scope, TypeLocation.TOPLEVEL);
switch(getUncheckedNullPolicy(false, functionalInterfaceType.getReturnType(), functionalMethod)) {
case Optional:
case UncheckedNull:
returnType = makeOptionalTypePreserveUnderlyingType(returnType, moduleScope);
break;
}
method.setType(returnType);
ParameterList pl = new ParameterList();
// List<VariableMirror> functionalParameters = functionalMethod.getParameters();
List<TypeMirror> parameterTypes = functionalInterfaceType.getParameterTypes();
Map<String, Integer> used = new HashMap<String, Integer>();
for (TypeMirror parameterType : parameterTypes) {
String name;
if (parameterTypes.size() == 1) {
name = "it";
} else {
switch(parameterType.getKind()) {
case ARRAY:
name = "array";
break;
case BOOLEAN:
name = "boolean";
break;
case CHAR:
name = "character";
break;
case BYTE:
name = "byte";
break;
case INT:
case LONG:
case SHORT:
name = "integer";
break;
case FLOAT:
case DOUBLE:
name = "float";
break;
case DECLARED:
String typeName = parameterType.getDeclaredClass().getName();
int first = typeName.codePointAt(0);
name = String.valueOf(Character.toChars(Character.toLowerCase(first))) + typeName.substring(Character.charCount(first));
break;
default:
name = "arg";
}
Integer count = used.get(name);
if (count == null) {
used.put(name, 1);
} else {
int next = count + 1;
used.put(name, next);
name += next;
}
}
Type modelParameterType = obtainType(moduleScope, parameterType, scope, TypeLocation.TOPLEVEL);
Parameter p = new Parameter();
Value v = new Value();
p.setName(name);
v.setName(name);
v.setContainer(method);
v.setScope(method);
p.setModel(v);
v.setInitializerParameter(p);
// Java parameters are all optional unless primitives or annotated as such
switch(getUncheckedNullPolicy(false, parameterType, functionalMethod)) {
case Optional:
modelParameterType = makeOptionalTypePreserveUnderlyingType(modelParameterType, moduleScope);
break;
case UncheckedNull:
v.setUncheckedNullType(true);
break;
}
v.setType(modelParameterType);
pl.getParameters().add(p);
method.addMember(v);
}
method.addParameterList(pl);
} catch (ModelResolutionException x) {
method.setType(logModelResolutionException(x, scope, "Failure to turn functional interface to Callable type"));
}
return method;
}
use of org.eclipse.ceylon.model.typechecker.model.Function in project ceylon by eclipse.
the class AbstractModelLoader method setParameters.
private void setParameters(Functional decl, ClassMirror classMirror, MethodMirror methodMirror, boolean isCeylon, Scope container, boolean isCoercedMethod) {
ParameterList parameters = new ParameterList();
parameters.setNamedParametersSupported(isCeylon);
decl.addParameterList(parameters);
int parameterCount = methodMirror.getParameters().size();
int parameterIndex = 0;
for (VariableMirror paramMirror : methodMirror.getParameters()) {
// ignore some parameters
if (paramMirror.getAnnotation(CEYLON_IGNORE_ANNOTATION) != null)
continue;
boolean isLastParameter = parameterIndex == parameterCount - 1;
boolean isVariadic = isLastParameter && methodMirror.isVariadic();
String paramName = getAnnotationStringValue(paramMirror, CEYLON_NAME_ANNOTATION);
// use whatever param name we find as default
if (paramName == null)
paramName = paramMirror.getName();
Parameter parameter = new Parameter();
parameter.setName(paramName);
TypeMirror typeMirror = paramMirror.getType();
Scope scope = (Scope) decl;
Module module = ModelUtil.getModuleContainer(scope);
Type type;
boolean coercedParameter = false;
if (isVariadic) {
// possibly make it optional
TypeMirror variadicType = typeMirror.getComponentType();
// we pretend it's toplevel because we want to get magic string conversion for variadic methods
if (isCoercedMethod && isCoercedType(variadicType)) {
type = applyTypeCoercion(variadicType, paramMirror, methodMirror, paramName, (Declaration) decl, module, scope);
coercedParameter = true;
} else {
type = obtainType(module, variadicType, scope, TypeLocation.TOPLEVEL);
}
if (!isCeylon) {
// Java parameters are all optional unless primitives or annotated as such
if (getUncheckedNullPolicy(isCeylon, variadicType, paramMirror) != NullStatus.NonOptional) {
type = makeOptionalTypePreserveUnderlyingType(type, module);
}
}
// turn it into a Sequential<T>
type = typeFactory.getSequentialType(type);
} else {
if (isCoercedMethod && isCoercedType(typeMirror)) {
type = applyTypeCoercion(typeMirror, paramMirror, methodMirror, paramName, (Declaration) decl, module, scope);
coercedParameter = true;
} else {
type = obtainType(typeMirror, paramMirror, scope, module, "parameter '" + paramName + "' of method '" + methodMirror.getName() + "'", (Declaration) decl);
}
if (!isCeylon) {
// Java parameters are all optional unless primitives or annotated as such
if (getUncheckedNullPolicy(isCeylon, typeMirror, paramMirror) != NullStatus.NonOptional) {
type = makeOptionalTypePreserveUnderlyingType(type, module);
}
}
}
if (type.isCached()) {
type = type.clone();
}
if (!type.isRaw())
type.setRaw(isRaw(ModelUtil.getModuleContainer(container), typeMirror));
FunctionOrValue value = null;
boolean lookedup = false;
if (isCeylon && decl instanceof Class) {
// For a functional parameter to a class, we can just lookup the member
value = (FunctionOrValue) ((Class) decl).getDirectMember(paramName, null, false);
lookedup = value != null;
}
if (value == null) {
// So either decl is not a Class,
// or the method or value member of decl is not shared
AnnotationMirror functionalParameterAnnotation = paramMirror.getAnnotation(CEYLON_FUNCTIONAL_PARAMETER_ANNOTATION);
if (functionalParameterAnnotation != null) {
// A functional parameter to a method
Function method = loadFunctionalParameter((Declaration) decl, paramName, type, (String) functionalParameterAnnotation.getValue());
value = method;
parameter.setDeclaredAnything(method.isDeclaredVoid());
} else if (coercedParameter && isFunctionCercion(typeMirror)) {
Function method = loadFunctionCoercionParameter((Declaration) decl, paramName, typeMirror, module, scope);
value = method;
parameter.setDeclaredAnything(method.isDeclaredVoid());
} else {
// A value parameter to a method
value = isCeylon ? new Value() : new JavaParameterValue();
value.setType(type);
}
value.setContainer(scope);
value.setScope(scope);
ModelUtil.setVisibleScope(value);
value.setUnit(scope.getUnit());
value.setName(paramName);
} else {
// the method return type, so we try to detect this and fix it
if (value instanceof Function && isCeylon1Dot1(classMirror)) {
Type newType = getSimpleCallableReturnType(value.getType());
if (!newType.isUnknown())
value.setType(newType);
}
}
value.setInitializerParameter(parameter);
value.setCoercionPoint(coercedParameter);
parameter.setModel(value);
if (paramMirror.getAnnotation(CEYLON_SEQUENCED_ANNOTATION) != null || isVariadic)
parameter.setSequenced(true);
if (paramMirror.getAnnotation(CEYLON_DEFAULTED_ANNOTATION) != null)
parameter.setDefaulted(true);
if (parameter.isSequenced() && // FIXME: store info in Sequenced
"ceylon.language.Sequence".equals(paramMirror.getType().getQualifiedName())) {
parameter.setAtLeastOne(true);
}
// unboxed is already set if it's a real method
if (!lookedup) {
// if it's variadic, consider the array element type (T[] == T...) for boxing rules
markUnboxed(value, null, isVariadic ? paramMirror.getType().getComponentType() : paramMirror.getType());
markSmall(value, paramMirror.getType());
}
parameter.setDeclaration((Declaration) decl);
value.setDeprecated(value.isDeprecated() || isDeprecated(paramMirror));
setAnnotations(value, paramMirror, false);
parameters.getParameters().add(parameter);
if (!lookedup) {
parameter.getDeclaration().getMembers().add(parameter.getModel());
}
parameterIndex++;
}
if (decl instanceof Function) {
// Multiple parameter lists
AnnotationMirror functionalParameterAnnotation = methodMirror.getAnnotation(CEYLON_FUNCTIONAL_PARAMETER_ANNOTATION);
if (functionalParameterAnnotation != null) {
parameterNameParser.parseMpl((String) functionalParameterAnnotation.getValue(), ((Function) decl).getType().getFullType(), (Function) decl);
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Function in project ceylon by eclipse.
the class JvmBackendUtil method getTopmostRefinedDeclaration.
public static Declaration getTopmostRefinedDeclaration(Declaration decl, Map<Function, Function> methodOverrides) {
if (decl instanceof FunctionOrValue && ((FunctionOrValue) decl).isParameter() && decl.getContainer() instanceof Class) {
// Parameters in a refined class are not considered refinements themselves
// We have in find the refined attribute
Class c = (Class) decl.getContainer();
boolean isAlias = c.isAlias();
boolean isActual = c.isActual();
// boxing and stuff
if (isAlias || isActual) {
Functional ctor = null;
int index = c.getParameterList().getParameters().indexOf(findParamForDecl(((TypedDeclaration) decl)));
// Note(Stef): not entirely sure about that one, what about aliases of actual classes?
while ((isAlias && c.isAlias()) || (isActual && c.isActual())) {
ctor = (isAlias && c.isAlias()) ? (Functional) ((ClassAlias) c).getConstructor() : c;
Type et = c.getExtendedType();
c = et != null && et.isClass() ? (Class) et.getDeclaration() : null;
// handle compile errors
if (c == null)
return null;
}
if (isActual) {
ctor = c;
}
// be safe
if (ctor == null || ctor.getParameterLists() == null || ctor.getParameterLists().isEmpty() || ctor.getFirstParameterList() == null || ctor.getFirstParameterList().getParameters() == null || ctor.getFirstParameterList().getParameters().size() <= index)
return null;
decl = ctor.getFirstParameterList().getParameters().get(index).getModel();
}
if (decl.isShared()) {
Declaration refinedDecl = c.getRefinedMember(decl.getName(), getSignature(decl), isVariadic(decl));
if (refinedDecl != null && !ModelUtil.equal(refinedDecl, decl)) {
return getTopmostRefinedDeclaration(refinedDecl, methodOverrides);
}
}
return decl;
} else if (decl instanceof FunctionOrValue && // a parameter
((FunctionOrValue) decl).isParameter() && (// that's not parameter of a functional parameter
(decl.getContainer() instanceof Function && !(((Function) decl.getContainer()).isParameter())) || // or is a parameter in a specification
decl.getContainer() instanceof Specification || (decl.getContainer() instanceof Function && ((Function) decl.getContainer()).isParameter() && createMethod((Function) decl.getContainer())))) {
// or is a class functional parameter
// Parameters in a refined method are not considered refinements themselves
// so we have to look up the corresponding parameter in the container's refined declaration
Functional func = (Functional) getParameterized((FunctionOrValue) decl);
if (func == null)
return decl;
Declaration kk = getTopmostRefinedDeclaration((Declaration) func, methodOverrides);
// error recovery
if (kk instanceof Functional == false)
return decl;
Functional refinedFunc = (Functional) kk;
// shortcut if the functional doesn't override anything
if (ModelUtil.equal((Declaration) refinedFunc, (Declaration) func)) {
return decl;
}
if (func.getParameterLists().size() != refinedFunc.getParameterLists().size()) {
// invalid input
return decl;
}
for (int ii = 0; ii < func.getParameterLists().size(); ii++) {
if (func.getParameterLists().get(ii).getParameters().size() != refinedFunc.getParameterLists().get(ii).getParameters().size()) {
// invalid input
return decl;
}
// find the index of the parameter in the declaration
int index = 0;
for (Parameter px : func.getParameterLists().get(ii).getParameters()) {
if (px.getModel() == null || px.getModel().equals(decl)) {
// And return the corresponding parameter from the refined declaration
return refinedFunc.getParameterLists().get(ii).getParameters().get(index).getModel();
}
index++;
}
continue;
}
} else if (methodOverrides != null && decl instanceof Function && ModelUtil.equal(decl.getRefinedDeclaration(), decl) && decl.getContainer() instanceof Specification && ((Specification) decl.getContainer()).getDeclaration() instanceof Function && ((Function) ((Specification) decl.getContainer()).getDeclaration()).isShortcutRefinement() && // hash lookup we do next to make sure it is really one of those cases
methodOverrides.containsKey(decl)) {
// special case for class X() extends T(){ m = function() => e; } which we inline
decl = methodOverrides.get(decl);
}
Declaration refinedDecl = decl.getRefinedDeclaration();
if (refinedDecl != null && !ModelUtil.equal(refinedDecl, decl))
return getTopmostRefinedDeclaration(refinedDecl);
return decl;
}
use of org.eclipse.ceylon.model.typechecker.model.Function in project ceylon by eclipse.
the class ConstructorDispatch method reflectionToMethodHandle.
private static MethodHandle reflectionToMethodHandle(Reference constructorReference, Member found, java.lang.Class<?> javaClass, Object instance, List<org.eclipse.ceylon.model.typechecker.model.Type> parameterProducedTypes, boolean jvmVarargs, boolean bindVariadicParameterToEmptyArray) {
// save the parameter types before we mess with "found"
java.lang.Class<?>[] parameterTypes;
java.lang.Class<?> returnType;
MethodHandle method = null;
boolean isJavaArray;
boolean isStatic;
int typeParametersCount;
int skipParameters = 0;
List<org.eclipse.ceylon.model.typechecker.model.TypeParameter> reifiedTypeParameters;
org.eclipse.ceylon.model.typechecker.model.Constructor constructorModel;
if (found instanceof java.lang.reflect.Method) {
org.eclipse.ceylon.model.typechecker.model.Generic functionModel = (org.eclipse.ceylon.model.typechecker.model.Generic) constructorReference.getDeclaration();
java.lang.reflect.Method foundMethod = (java.lang.reflect.Method) found;
parameterTypes = foundMethod.getParameterTypes();
returnType = foundMethod.getReturnType();
isStatic = Modifier.isStatic(foundMethod.getModifiers());
isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
typeParametersCount = javaClass.getTypeParameters().length;
try {
if (isJavaArray) {
if (foundMethod.getName().equals("get"))
method = MethodHandleUtil.getJavaArrayGetterMethodHandle(javaClass);
else if (foundMethod.getName().equals("set"))
method = MethodHandleUtil.getJavaArraySetterMethodHandle(javaClass);
else if (foundMethod.getName().equals("copyTo")) {
found = MethodHandleUtil.getJavaArrayCopyToMethod(javaClass, foundMethod);
}
}
if (method == null) {
foundMethod.setAccessible(true);
method = MethodHandles.lookup().unreflect(foundMethod);
}
} catch (IllegalAccessException e) {
throw Metamodel.newModelError("Problem getting a MH for constructor for: " + javaClass, e);
}
reifiedTypeParameters = functionModel.getTypeParameters();
if (isJavaArray && "objectArrayConstructor".equals(foundMethod.getName())) {
reifiedTypeParameters = ((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) ((Declaration) functionModel).getContainer()).getTypeParameters();
}
constructorModel = null;
} else if (found instanceof java.lang.reflect.Constructor<?>) {
org.eclipse.ceylon.model.typechecker.model.Declaration functionOrConstructorModel = constructorReference.getDeclaration();
java.lang.reflect.Constructor<?> foundMethod = (java.lang.reflect.Constructor<?>) found;
parameterTypes = foundMethod.getParameterTypes();
returnType = javaClass;
isStatic = Modifier.isStatic(foundMethod.getDeclaringClass().getModifiers());
foundMethod.setAccessible(true);
try {
method = MethodHandles.lookup().unreflectConstructor(foundMethod);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
isJavaArray = false;
typeParametersCount = javaClass.getTypeParameters().length;
if (javaClass.isMemberClass() && Modifier.isStatic(javaClass.getModifiers())) {
typeParametersCount += javaClass.getEnclosingClass().getTypeParameters().length;
}
if (functionOrConstructorModel instanceof org.eclipse.ceylon.model.typechecker.model.Constructor) {
constructorModel = (org.eclipse.ceylon.model.typechecker.model.Constructor) functionOrConstructorModel;
reifiedTypeParameters = ModelUtil.getConstructedClass(constructorModel).getTypeParameters();
} else if (functionOrConstructorModel instanceof Function) {
constructorModel = (org.eclipse.ceylon.model.typechecker.model.Constructor) ((Function) functionOrConstructorModel).getTypeDeclaration();
reifiedTypeParameters = ModelUtil.getConstructedClass(constructorModel).getTypeParameters();
} else if (functionOrConstructorModel instanceof org.eclipse.ceylon.model.typechecker.model.Class) {
constructorModel = null;
reifiedTypeParameters = ((org.eclipse.ceylon.model.typechecker.model.Class) functionOrConstructorModel).getTypeParameters();
} else {
throw new RuntimeException();
}
} else {
throw new RuntimeException();
}
boolean isJavaMember = found instanceof java.lang.reflect.Constructor && instance != null && !isStatic;
// box the return type
method = MethodHandleUtil.boxReturnValue(method, returnType, constructorReference.getType());
// until we have casted it first
if (isJavaMember) {
method = method.asType(MethodType.methodType(Object.class, parameterTypes));
}
if (instance != null && (isJavaArray || !isStatic)) {
method = method.bindTo(instance);
}
// if it was not a java member we have no extra synthetic instance parameter and we need to get rid of it before casting
if (!isJavaMember) {
method = method.asType(MethodType.methodType(Object.class, parameterTypes));
}
if (isJavaMember) {
// skip the first parameter for boxing
skipParameters++;
}
// insert any required type descriptors
if (typeParametersCount != 0 && MethodHandleUtil.isReifiedTypeSupported(found, isJavaMember)) {
List<org.eclipse.ceylon.model.typechecker.model.Type> typeArguments = new ArrayList<org.eclipse.ceylon.model.typechecker.model.Type>();
java.util.Map<org.eclipse.ceylon.model.typechecker.model.TypeParameter, org.eclipse.ceylon.model.typechecker.model.Type> typeArgumentMap = constructorReference.getTypeArguments();
for (org.eclipse.ceylon.model.typechecker.model.TypeParameter tp : reifiedTypeParameters) {
typeArguments.add(typeArgumentMap.get(tp));
}
method = MethodHandleUtil.insertReifiedTypeArguments(method, 0, typeArguments);
skipParameters += typeParametersCount;
}
// Now, if it's a constructor we need to insert the (null) constructor name argument
if (constructorModel != null && constructorModel.getName() != null && !constructorModel.getName().isEmpty()) {
method = MethodHandleUtil.insertConstructorNameArgument(method, 0, constructorModel);
skipParameters += 1;
}
// now convert all arguments (we may need to unbox)
method = MethodHandleUtil.unboxArguments(method, skipParameters, 0, parameterTypes, parameterProducedTypes, jvmVarargs, bindVariadicParameterToEmptyArray);
return method;
}
use of org.eclipse.ceylon.model.typechecker.model.Function in project ceylon by eclipse.
the class ExpressionVisitor method visit.
@Override
public void visit(Tree.MethodDeclaration that) {
super.visit(that);
Tree.Type type = that.getType();
Function fun = that.getDeclarationModel();
Tree.SpecifierExpression se = that.getSpecifierExpression();
if (se != null) {
Tree.Expression e = se.getExpression();
if (e != null) {
if (!fun.isActual() || // & RV.checkRefinedMemberTypeAssignable()
isTypeUnknown(fun.getType())) {
inferFunctionType(that, e);
}
if (type != null && !(type instanceof Tree.DynamicModifier)) {
checkFunctionType(e, type, se);
}
if (type instanceof Tree.VoidModifier && !isSatementExpression(e)) {
se.addError("function is declared void so specified expression must be a statement: '" + fun.getName() + "' is declared 'void'", 210);
}
}
}
if (type instanceof Tree.LocalModifier) {
if (fun.isParameter()) {
type.addError("parameter may not have inferred type: '" + fun.getName() + "' must declare an explicit type");
} else if (isTypeUnknown(type.getTypeModel())) {
if (se == null) {
type.addError("function must specify an explicit return type or definition", 200);
} else if (!hasError(se)) {
type.addError("function type could not be inferred");
}
}
}
}
Aggregations