use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class RefinementVisitor method visit.
@Override
public void visit(Tree.Declaration that) {
super.visit(that);
Declaration dec = that.getDeclarationModel();
if (dec != null) {
boolean mayBeShared = dec.isToplevel() || dec.isClassOrInterfaceMember();
if (dec.isShared() && !mayBeShared) {
that.addError("shared declaration is not a member of a class, interface, or package: " + message(dec) + " may not be annotated 'shared'", 1200);
}
boolean mayBeRefined = dec instanceof Value || dec instanceof Function || dec instanceof Class;
if (!mayBeRefined) {
checkNonrefinableDeclaration(that, dec);
}
boolean member = dec.isClassOrInterfaceMember() && dec.isShared() && !isConstructor(dec) && // TODO: what about nested interfaces and abstract classes?!
!(dec instanceof TypeParameter);
if (member) {
checkMember(that, dec);
} else {
checkNonMember(that, dec);
}
if (dec.isNativeImplementation() || isNativeMember(dec)) {
checkNative(that, dec);
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class RefinementVisitor method checkRefiningMemberUpperBounds.
private List<Type> checkRefiningMemberUpperBounds(Tree.Declaration that, ClassOrInterface ci, Declaration refined, List<TypeParameter> refinedTypeParams, List<TypeParameter> refiningTypeParams) {
int refiningSize = refiningTypeParams.size();
int refinedSize = refinedTypeParams.size();
int max = refiningSize <= refinedSize ? refiningSize : refinedSize;
if (max == 0) {
return NO_TYPE_ARGS;
}
// we substitute the type parameters of the refined
// declaration into the bounds of the refining
// declaration
Map<TypeParameter, Type> substitution = new HashMap<TypeParameter, Type>();
for (int i = 0; i < max; i++) {
TypeParameter refinedTypeParam = refinedTypeParams.get(i);
TypeParameter refiningTypeParam = refiningTypeParams.get(i);
substitution.put(refiningTypeParam, refinedTypeParam.getType());
}
Map<TypeParameter, SiteVariance> noVariances = emptyMap();
TypeDeclaration rc = (TypeDeclaration) refined.getContainer();
// we substitute the type arguments of the subtype's
// instantiation of the supertype into the bounds of
// the refined declaration
Type supertype = ci.getType().getSupertype(rc);
Map<TypeParameter, Type> args = supertype.getTypeArguments();
Map<TypeParameter, SiteVariance> variances = supertype.getVarianceOverrides();
List<Type> typeArgs = new ArrayList<Type>(max);
for (int i = 0; i < max; i++) {
TypeParameter refinedTypeParam = refinedTypeParams.get(i);
TypeParameter refiningTypeParam = refiningTypeParams.get(i);
refiningTypeParam.setReified(refinedTypeParam.isReified());
Type refinedProducedType = refinedTypeParam.getType();
List<Type> refinedBounds = refinedTypeParam.getSatisfiedTypes();
List<Type> refiningBounds = refiningTypeParam.getSatisfiedTypes();
Unit unit = that.getUnit();
for (Type bound : refiningBounds) {
Type refiningBound = bound.substitute(substitution, noVariances);
// for every type constraint of the refining member, there must
// be at least one type constraint of the refined member which
// is assignable to it, guaranteeing that the intersection of
// the refined member bounds is assignable to the intersection
// of the refining member bounds
// TODO: would it be better to just form the intersections and
// test assignability directly (the error messages might
// not be as helpful, but it might be less restrictive)
boolean ok = false;
for (Type refinedBound : refinedBounds) {
refinedBound = refinedBound.substitute(args, variances);
if (refinedBound.isSubtypeOf(refiningBound)) {
ok = true;
}
}
if (!ok) {
that.addError("refining member type parameter '" + refiningTypeParam.getName() + "' has upper bound which refined member type parameter '" + refinedTypeParam.getName() + "' of " + message(refined) + " does not satisfy: '" + bound.asString(unit) + "' ('" + refiningTypeParam.getName() + "' should be upper bounded by '" + intersectionOfSupertypes(refinedTypeParam).substitute(args, variances).asString(unit) + "')");
}
}
for (Type bound : refinedBounds) {
Type refinedBound = bound.substitute(args, variances);
boolean ok = false;
for (Type refiningBound : refiningBounds) {
refiningBound = refiningBound.substitute(substitution, noVariances);
if (refinedBound.isSubtypeOf(refiningBound)) {
ok = true;
}
}
if (!ok) {
that.addUnsupportedError("refined member type parameter '" + refinedTypeParam.getName() + "' of " + message(refined) + " has upper bound which refining member type parameter '" + refiningTypeParam.getName() + "' does not satisfy: '" + bound.asString(unit) + "' ('" + refiningTypeParam.getName() + "' should be upper bounded by '" + intersectionOfSupertypes(refinedTypeParam).substitute(args, variances).asString(unit) + "')");
}
}
typeArgs.add(refinedProducedType);
}
return typeArgs;
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class RefinementVisitor method createRefiningParameterList.
private void createRefiningParameterList(Reference rm, Function method, Tree.ParameterList params, Unit unit, Map<TypeParameter, Type> subs, ParameterList pl) {
ParameterList list = new ParameterList();
int j = 0;
for (Parameter p : pl.getParameters()) {
// TODO: meaningful errors when parameters don't line up
// currently this is handled elsewhere, but we can
// probably do it better right here
createRefiningParameter(rm, method, p, list, params, j++, subs, unit);
}
method.getParameterLists().add(list);
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeArgumentInference method getInferredTypeArgsForTypeConstructor.
/**
* Infer type arguments for a generic function reference
* that occurs within the primary of an invocation
* expression.
*
* @param that the invocation
* @param receiverType the qualifying type
* @param type the type constructor
* @param typeParameters the type parameters to infer
*
* @return the type arguments
*/
List<Type> getInferredTypeArgsForTypeConstructor(Tree.InvocationExpression that, Type receiverType, Type type, List<TypeParameter> typeParameters) {
Tree.PositionalArgumentList pal = that.getPositionalArgumentList();
if (pal == null) {
return null;
} else {
List<Type> typeArguments = new ArrayList<Type>();
for (TypeParameter tp : typeParameters) {
List<Type> paramTypes = unit.getCallableArgumentTypes(type);
Type paramTypesAsTuple = unit.getCallableTuple(type);
boolean sequenced = unit.isTupleLengthUnbounded(paramTypesAsTuple);
int argCount = pal.getPositionalArguments().size();
boolean findUpperBounds = isEffectivelyContravariant(tp, type, argCount);
Type it = inferTypeArgumentFromPositionalArgs(tp, paramTypes, paramTypesAsTuple, sequenced, receiverType, pal, findUpperBounds);
typeArguments.add(it);
}
// TODO: apply type constraints!!
return typeArguments;
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeArgumentInference method getInferredTypeArgsForStaticReference.
/**
* Infer type arguments for the qualifying type in a
* static method reference that is directly invoked.
* This method does not correctly handle stuff like
* constructors or Java static methods.
*
* @param that the invocation
* @param type the type whose type arguments we're
* inferring (the qualifying type)
* @param receiverType
*/
List<Type> getInferredTypeArgsForStaticReference(Tree.InvocationExpression that, TypeDeclaration type, Type receiverType, Tree.MemberOrTypeExpression primary) {
Tree.PositionalArgumentList pal = that.getPositionalArgumentList();
Declaration invoked = primary.getDeclaration();
if (pal == null) {
return null;
} else {
if (invoked instanceof Functional) {
List<PositionalArgument> args = pal.getPositionalArguments();
Functional fun = (Functional) invoked;
List<ParameterList> parameterLists = fun.getParameterLists();
if (args.isEmpty() || parameterLists.isEmpty()) {
return null;
} else {
// a static method ref invocation has exactly
// one meaningful argument (the instance of
// the receiving type)
Tree.PositionalArgument arg = args.get(0);
if (arg == null) {
return null;
} else {
Type at = arg.getTypeModel();
Type tt = type.getType();
List<TypeParameter> typeParams = type.getTypeParameters();
List<Type> typeArgs = new ArrayList<Type>(typeParams.size());
for (TypeParameter tp : typeParams) {
Type it = inferTypeArg(tp, tt, at, // TODO: is this 100% correct?
false, arg);
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(typeParams, typeArgs, receiverType, invoked);
}
}
} else {
return null;
}
}
}
Aggregations