use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class TypeArgumentInference method inferFunctionRefTypeArgs.
/**
* Infer type arguments for a direct function
* ref (i.e. not a value ref with a type
* constructor type) that occurs as an argument
* to a callable parameter.
*/
private List<Type> inferFunctionRefTypeArgs(Tree.StaticMemberOrTypeExpression smte, Type receiverType, boolean secondList, Declaration reference, List<TypeParameter> typeParameters, TypedReference paramTypedRef, Declaration paramDec, Declaration parameterizedDec) {
Reference arg = appliedReference(smte);
Functional fun = (Functional) reference;
List<ParameterList> apls = fun.getParameterLists();
Functional pfun = (Functional) paramDec;
List<ParameterList> ppls = pfun.getParameterLists();
if (apls.isEmpty() || ppls.isEmpty()) {
// TODO: to give a nicer error
return null;
} else {
ParameterList aplf = apls.get(secondList ? 1 : 0);
ParameterList pplf = ppls.get(0);
List<Parameter> apl = aplf.getParameters();
List<Parameter> ppl = pplf.getParameters();
boolean[] specifiedParams = specifiedParameters(apl.size(), ppl.size());
List<Type> inferredTypes = new ArrayList<Type>(typeParameters.size());
for (TypeParameter tp : typeParameters) {
boolean findUpperBounds = isEffectivelyContravariant(tp, reference, specifiedParams, secondList);
Type it = inferFunctionRefTypeArg(smte, tp, typeParameters, paramTypedRef, parameterizedDec, arg, apl, ppl, findUpperBounds);
inferredTypes.add(it);
}
return constrainInferredTypes(typeParameters, inferredTypes, receiverType, reference);
}
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class TypeArgumentInference method getInferredTypeArgsForReference.
/**
* Infer type arguments for a given generic declaration,
* using the value arguments of an invocation of a given
* declaration.
*
* @param that the invocation
* @param invoked the thing actually being invoked
* @param generic the thing we're inferring type
* arguments for, which may not be the thing
* actually being invoked
* @param receiverType
*
* @return a list of inferred type arguments
*/
List<Type> getInferredTypeArgsForReference(Tree.InvocationExpression that, Declaration invoked, Declaration generic, Type receiverType) {
if (invoked instanceof Functional) {
Functional functional = (Functional) invoked;
List<ParameterList> parameterLists = functional.getParameterLists();
if (parameterLists.isEmpty()) {
return null;
} else {
List<Type> typeArgs = new ArrayList<Type>();
List<TypeParameter> typeParameters = generic.getTypeParameters();
for (TypeParameter tp : typeParameters) {
ParameterList pl = parameterLists.get(0);
Type it = inferTypeArgument(that, receiverType, tp, pl, invoked);
if (it == null || it.containsUnknowns()) {
that.addError("could not infer type argument from given arguments: type parameter '" + tp.getName() + "' could not be inferred");
}
typeArgs.add(it);
}
return constrainInferredTypes(typeParameters, typeArgs, receiverType, invoked);
}
} else {
return null;
}
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class TypeHierarchyVisitor method checkForFormalsNotImplemented.
private void checkForFormalsNotImplemented(Node that, List<Type> orderedTypes, Class clazz) {
Type aggregation = buildAggregatedType(orderedTypes);
for (Type.Members members : aggregation.membersByName.values()) {
if (!members.formals.isEmpty()) {
if (members.actualsNonFormals.isEmpty()) {
Declaration example = members.formals.iterator().next();
Declaration declaringType = (Declaration) example.getContainer();
if (!clazz.equals(declaringType)) {
String name = example.getName();
if (isJavaSetter(example) && aggregation.membersByName.containsKey(setterToProperty(name))) {
// (i.e. a setter with no getter)
continue;
}
addUnimplementedFormal(clazz, example);
that.addError("formal member '" + name + "' of '" + declaringType.getName() + "' not implemented for concrete class '" + clazz.getName() + "': '" + clazz.getName() + "' neither directly implements nor inherits a concrete implementation of '" + name + "'", 300);
continue;
}
}
for (Declaration f : members.formals) {
if (isOverloadedVersion(f) && !f.isCoercionPoint()) {
boolean found = false;
// boolean variadic = f.isVariadic();
for (Declaration a : members.actualsNonFormals) {
if (f.getRefinedDeclaration().equals(a.getRefinedDeclaration())) {
found = true;
break;
}
}
if (!found) {
StringBuilder paramTypes = new StringBuilder();
List<ParameterList> parameterLists = ((Functional) f).getParameterLists();
if (!parameterLists.isEmpty()) {
for (Parameter p : parameterLists.get(0).getParameters()) {
if (paramTypes.length() > 0) {
paramTypes.append(", ");
}
if (!isTypeUnknown(p.getType())) {
paramTypes.append(p.getType().asString());
}
}
}
Declaration declaringType = (Declaration) f.getContainer();
addUnimplementedFormal(clazz, f);
that.addError("overloaded formal member '" + f.getName() + "(" + paramTypes + ")' of '" + declaringType.getName() + "' not implemented in class hierarchy");
}
}
}
}
/*if (!members.concretesOnInterfaces.isEmpty() && members.actualsNonFormals.isEmpty()) {
Declaration declaringType = (Declaration) members.concretesOnInterfaces.iterator().next().getContainer();
that.addWarning("interface member " + members.name +
" of " + declaringType.getName() +
" not implemented in class hierarchy (concrete interface members not yet supported)");
}*/
}
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class AnnotationVisitor method visit.
@Override
public void visit(Tree.DocLink that) {
super.visit(that);
String text = that.getText();
int pipeIndex = text.indexOf("|");
if (pipeIndex != -1) {
text = text.substring(pipeIndex + 1);
}
String kind = null;
if (text.startsWith(DOC_LINK_MODULE)) {
kind = DOC_LINK_MODULE;
text = text.substring(DOC_LINK_MODULE.length());
} else if (text.startsWith(DOC_LINK_PACKAGE)) {
kind = DOC_LINK_PACKAGE;
text = text.substring(DOC_LINK_PACKAGE.length());
} else if (text.startsWith(DOC_LINK_CLASS)) {
kind = DOC_LINK_CLASS;
text = text.substring(DOC_LINK_CLASS.length());
} else if (text.startsWith(DOC_LINK_INTERFACE)) {
kind = DOC_LINK_INTERFACE;
text = text.substring(DOC_LINK_INTERFACE.length());
} else if (text.startsWith(DOC_LINK_FUNCTION)) {
kind = DOC_LINK_FUNCTION;
text = text.substring(DOC_LINK_FUNCTION.length());
} else if (text.startsWith(DOC_LINK_VALUE)) {
kind = DOC_LINK_VALUE;
text = text.substring(DOC_LINK_VALUE.length());
} else if (text.startsWith(DOC_LINK_ALIAS)) {
kind = DOC_LINK_ALIAS;
text = text.substring(DOC_LINK_ALIAS.length());
}
boolean parentheses = false;
if (text.endsWith("()")) {
parentheses = true;
text = text.substring(0, text.length() - 2);
}
int scopeIndex = text.indexOf("::");
String packageName;
if (DOC_LINK_MODULE.equals(kind) || DOC_LINK_PACKAGE.equals(kind)) {
packageName = text;
} else {
packageName = scopeIndex < 0 ? null : text.substring(0, scopeIndex);
}
String path = scopeIndex < 0 ? text : text.substring(scopeIndex + 2);
String[] names = path.isEmpty() ? new String[0] : path.split("\\.");
Declaration base = null;
if (packageName == null) {
if (names.length > 0) {
base = that.getScope().getMemberOrParameter(that.getUnit(), names[0], null, false);
}
} else {
Package pack = that.getUnit().getPackage().getModule().getPackage(packageName);
if (pack == null) {
if (DOC_LINK_MODULE.equals(kind)) {
that.addUsageWarning(Warning.doclink, "module is missing: '" + packageName + "'");
} else {
that.addUsageWarning(Warning.doclink, "package is missing: '" + packageName + "'");
}
} else {
that.setPkg(pack);
if (DOC_LINK_MODULE.equals(kind)) {
Package rootPack = pack.getModule().getRootPackage();
if (pack.equals(rootPack)) {
that.setModule(pack.getModule());
} else {
that.addUsageWarning(Warning.doclink, "module is missing: '" + packageName + "'");
}
}
if (names.length > 0) {
base = pack.getDirectMember(names[0], null, false);
}
}
if (DOC_LINK_MODULE.equals(kind) || DOC_LINK_PACKAGE.equals(kind)) {
return;
}
}
if (base == null) {
that.addUsageWarning(Warning.doclink, "declaration is missing: '" + (names.length > 0 ? names[0] : text) + "'");
} else {
that.setBase(base);
if (names.length > 1) {
that.setQualified(new ArrayList<Declaration>(names.length - 1));
}
for (int i = 1; i < names.length; i++) {
if (base instanceof Value) {
Value value = (Value) base;
if (!value.isParameter() && !value.isTransient() && value.getTypeDeclaration() != null && value.getTypeDeclaration().isAnonymous()) {
base = value.getTypeDeclaration();
}
}
if (base instanceof TypeDeclaration || base instanceof Functional) {
Declaration qualified = base.getMember(names[i], null, false);
if (qualified == null) {
that.addUsageWarning(Warning.doclink, "member declaration or parameter is missing: '" + names[i] + "'");
break;
} else {
that.getQualified().add(qualified);
base = qualified;
}
} else {
that.addUsageWarning(Warning.doclink, "not a type or functional declaration: '" + base.getName() + "'");
break;
}
}
}
if (base != null) {
if (kind != null && (names.length == 1 || names.length == that.getQualified().size() + 1)) {
if (DOC_LINK_CLASS.equals(kind) && !(base instanceof Class)) {
that.addUsageWarning(Warning.doclink, "linked declaration is not a class: '" + base.getName() + "'");
} else if (DOC_LINK_INTERFACE.equals(kind) && !(base instanceof Interface)) {
that.addUsageWarning(Warning.doclink, "linked declaration is not an interface: '" + base.getName() + "'");
} else if (DOC_LINK_ALIAS.equals(kind) && !(base instanceof TypeAlias)) {
that.addUsageWarning(Warning.doclink, "linked declaration is not a type alias: '" + base.getName() + "'");
} else if (DOC_LINK_FUNCTION.equals(kind) && !(base instanceof Function)) {
that.addUsageWarning(Warning.doclink, "linked declaration is not a function: '" + base.getName() + "'");
} else if (DOC_LINK_VALUE.equals(kind) && !(base instanceof Value)) {
that.addUsageWarning(Warning.doclink, "linked declaration is not a value: '" + base.getName() + "'");
}
}
if (parentheses && !(base instanceof Functional)) {
that.addUsageWarning(Warning.doclink, "linked declaration is not a function: '" + base.getName() + "'");
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Functional in project ceylon by eclipse.
the class InvocationGenerator method positionalInvocation.
private void positionalInvocation(final Tree.InvocationExpression that) {
final Tree.Primary typeArgSource = that.getPrimary();
final Tree.PositionalArgumentList argList = that.getPositionalArgumentList();
final Map<TypeParameter, Type> targs = getTypeArguments(typeArgSource);
if (gen.isInDynamicBlock() && typeArgSource instanceof Tree.BaseTypeExpression && ((Tree.BaseTypeExpression) typeArgSource).getDeclaration() == null) {
gen.out("(");
// Could be a dynamic object, or a Ceylon one
// We might need to call "new" so we need to get all the args to pass directly later
final List<String> argnames = generatePositionalArguments(typeArgSource, argList, argList.getPositionalArguments(), false, true);
if (!argnames.isEmpty()) {
gen.out(",");
}
final String fname = names.createTempVariable();
gen.out(fname, "=");
typeArgSource.visit(gen);
String theargs = "";
if (!argnames.isEmpty()) {
theargs = argnames.toString().substring(1);
theargs = theargs.substring(0, theargs.length() - 1);
}
gen.out(",", fname, ".$$===undefined?new ", fname, "(", theargs, "):", fname, "(", theargs, "))");
// TODO we lose type args for now
return;
} else {
final Tree.PositionalArgument lastArg = argList.getPositionalArguments().isEmpty() ? null : argList.getPositionalArguments().get(argList.getPositionalArguments().size() - 1);
boolean hasSpread = lastArg instanceof Tree.SpreadArgument && that.getUnit().isUnknownArgumentsCallable(that.getPrimary().getTypeModel()) && !typeArgSource.getTypeModel().isUnknown();
if (hasSpread) {
gen.out(gen.getClAlias(), "spread$2(");
}
if (typeArgSource instanceof Tree.BaseMemberExpression) {
final Tree.BaseMemberExpression _bme = (Tree.BaseMemberExpression) typeArgSource;
if (gen.isInDynamicBlock()) {
if (_bme.getDeclaration() == null || _bme.getDeclaration().isDynamic() || (_bme.getDeclaration() instanceof TypedDeclaration && ((TypedDeclaration) _bme.getDeclaration()).isDynamicallyTyped())) {
if (lastArg instanceof Tree.SpreadArgument && (lastArg.getTypeModel() == null || lastArg.getTypeModel().isUnknown())) {
BmeGenerator.generateBme(_bme, gen);
gen.out(".apply(0,");
if (argList.getPositionalArguments().size() == 1) {
generatePositionalArguments(typeArgSource, argList, argList.getPositionalArguments(), false, true);
} else {
gen.out("[");
ArrayList<Tree.PositionalArgument> subargs = new ArrayList<>(argList.getPositionalArguments().size());
subargs.addAll(argList.getPositionalArguments());
subargs.remove(subargs.size() - 1);
generatePositionalArguments(typeArgSource, argList, subargs, false, true);
gen.out("].concat(");
lastArg.visit(gen);
gen.out(")");
}
gen.out(")");
return;
}
} else if ("ceylon.language::print".equals(_bme.getDeclaration().getQualifiedNameString())) {
Tree.PositionalArgument printArg = that.getPositionalArgumentList().getPositionalArguments().get(0);
if (ModelUtil.isTypeUnknown(printArg.getTypeModel())) {
// #397
gen.out(gen.getClAlias(), "pndo$(");
printArg.visit(gen);
gen.out(")");
return;
}
}
}
BmeGenerator.generateBme(_bme, gen);
} else if (typeArgSource instanceof Tree.QualifiedTypeExpression) {
BmeGenerator.generateQte((Tree.QualifiedTypeExpression) typeArgSource, gen);
} else {
typeArgSource.visit(gen);
}
if (gen.opts.isOptimize() && (gen.getSuperMemberScope(typeArgSource) != null)) {
gen.out(".call(", names.self(ModelUtil.getContainingClassOrInterface(typeArgSource.getScope())));
if (!argList.getPositionalArguments().isEmpty()) {
gen.out(",");
}
} else if (hasSpread) {
gen.out(",");
} else {
gen.out("(");
}
// Check if args have params
boolean fillInParams = !argList.getPositionalArguments().isEmpty();
for (Tree.PositionalArgument arg : argList.getPositionalArguments()) {
fillInParams &= arg.getParameter() == null;
}
if (fillInParams) {
// Get the callable and try to assign params from there
Interface cd = that.getUnit().getCallableDeclaration();
final Type ed = that.getUnit().getEmptyType();
Class td = that.getUnit().getTupleDeclaration();
Type callable = typeArgSource.getTypeModel() == null ? null : typeArgSource.getTypeModel().getSupertype(cd);
if (callable != null) {
// This is a tuple with the arguments to the callable
// (can be union with empty if first param is defaulted)
Type callableArgs = callable.getTypeArgumentList().get(1);
boolean isUnion = false;
if (callableArgs.isUnion()) {
if (callableArgs.getCaseTypes().size() == 2) {
callableArgs = callableArgs.minus(ed);
}
isUnion = callableArgs.isUnion();
}
// This is the type of the first argument
boolean isSequenced = !(isUnion || td.equals(callableArgs.getDeclaration()));
Type argtype = isUnion ? callableArgs : callableArgs.isTypeParameter() || callableArgs.isEmpty() ? callableArgs : callableArgs.isSequence() || callableArgs.isSequential() ? callableArgs.getTypeArgumentList().get(0) : callableArgs.getTypeArgumentList().get(isSequenced ? 0 : 1);
Parameter p = null;
int c = 0;
for (Tree.PositionalArgument arg : argList.getPositionalArguments()) {
if (p == null) {
p = new Parameter();
p.setName("arg" + c);
p.setDeclaration(typeArgSource.getTypeModel().getDeclaration());
Value v = new Value();
Scope scope = that.getPositionalArgumentList().getScope();
v.setContainer(scope);
v.setScope(scope);
v.setType(argtype);
p.setModel(v);
if (callableArgs == null || isSequenced) {
p.setSequenced(true);
} else if (!isSequenced) {
Type next = isUnion ? null : callableArgs.getTypeArgumentList().get(2);
if (next != null && next.getSupertype(td) == null) {
// sequential if sequenced param
if (next.isUnion()) {
// empty|tuple
callableArgs = next.minus(ed);
isSequenced = !td.equals(callableArgs.getDeclaration());
argtype = callableArgs.getTypeArgumentList().get(isSequenced ? 0 : 1);
} else {
// we'll bet on sequential (if it's empty we don't care anyway)
argtype = next;
callableArgs = null;
}
} else {
// If it's a tuple then there are more params
callableArgs = next;
argtype = callableArgs == null ? null : callableArgs.getTypeArgumentList().get(1);
}
}
}
arg.setParameter(p);
c++;
if (!p.isSequenced()) {
p = null;
}
}
}
}
generatePositionalArguments(typeArgSource, argList, argList.getPositionalArguments(), false, false);
}
if (targs != null && !targs.isEmpty() && typeArgSource instanceof Tree.MemberOrTypeExpression && ((Tree.MemberOrTypeExpression) typeArgSource).getDeclaration() instanceof Functional) {
if (argList.getPositionalArguments().size() > 0) {
gen.out(",");
}
Functional bmed = (Functional) ((Tree.MemberOrTypeExpression) typeArgSource).getDeclaration();
// If there are fewer arguments than there are parameters...
final int argsSize = argList.getPositionalArguments().size();
int paramArgDiff = bmed.getFirstParameterList().getParameters().size() - argsSize;
if (paramArgDiff > 0) {
final Tree.PositionalArgument parg = argsSize > 0 ? argList.getPositionalArguments().get(argsSize - 1) : null;
if (parg instanceof Tree.Comprehension || parg instanceof Tree.SpreadArgument) {
paramArgDiff--;
}
for (int i = 0; i < paramArgDiff; i++) {
gen.out("undefined,");
}
}
if (targs != null && !targs.isEmpty()) {
TypeUtils.printTypeArguments(typeArgSource, targs, gen, false, null);
}
}
gen.out(")");
}
Aggregations