use of org.eclipse.ceylon.compiler.typechecker.tree.Node in project ceylon by eclipse.
the class ExpressionVisitor method warnUncheckedNulls.
private static void warnUncheckedNulls(Tree.LocalModifier local, Type type, Tree.Term term) {
// often the LocalModifier doesn't have location info
Node node = term == null ? local : term;
Unit unit = local.getUnit();
if (term instanceof Tree.InvocationExpression) {
Tree.InvocationExpression ie = (Tree.InvocationExpression) term;
Tree.Term p = ie.getPrimary();
if (p instanceof Tree.StaticMemberOrTypeExpression) {
Tree.StaticMemberOrTypeExpression bme = (Tree.StaticMemberOrTypeExpression) p;
Declaration dec = bme.getDeclaration();
if (dec != null) {
String str = type.asSourceCodeString(unit);
node.addUsageWarning(Warning.inferredNotNull, "not null type inferred from invocation of function with unchecked nulls: '" + dec.getName(unit) + "' is not known to be null-safe (explicitly specify the type '" + str + "' or '" + str + "?')");
return;
}
}
} else if (term instanceof Tree.StaticMemberOrTypeExpression) {
Tree.StaticMemberOrTypeExpression bme = (Tree.StaticMemberOrTypeExpression) term;
Declaration dec = bme.getDeclaration();
if (dec != null) {
String str = type.asSourceCodeString(unit);
node.addUsageWarning(Warning.inferredNotNull, "not null type inferred from reference to value with unchecked nulls: '" + dec.getName(unit) + "' is not known to be null-safe (explicitly specify the type '" + str + "' or '" + str + "?')");
return;
}
}
String str = type.asSourceCodeString(unit);
node.addUsageWarning(Warning.inferredNotNull, "not null type inferred from reference to function or value with unchecked nulls (explicitly specify the type '" + str + "' or '" + str + "?')");
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Node in project ceylon by eclipse.
the class ExpressionVisitor method destructureTuple.
private void destructureTuple(Type sequenceType, Tree.TuplePattern tuplePattern) {
List<Tree.Pattern> patterns = tuplePattern.getPatterns();
int length = patterns.size();
Tree.Pattern lastPattern = patterns.get(length - 1);
boolean variadic = isVariadicPattern(lastPattern);
List<Type> types = unit.getTupleElementTypes(sequenceType);
boolean tupleLengthUnbounded = unit.isTupleLengthUnbounded(sequenceType);
// boolean tupleVariantAtLeastOne =
// unit.isTupleVariantAtLeastOne(sequenceType);
int minimumLength = unit.getTupleMinimumLength(sequenceType);
if (!variadic && types.size() > length) {
tuplePattern.addError("assigned tuple has too many elements");
}
if (!variadic && tupleLengthUnbounded) {
tuplePattern.addError("assigned tuple has unbounded length");
}
if (!variadic && minimumLength < types.size()) {
tuplePattern.addError("assigned tuple has variadic length");
}
int fixedLength = variadic ? length - 1 : length;
for (int i = 0; i < types.size() && i < fixedLength; i++) {
Type type = types.get(i);
Tree.Pattern pattern = patterns.get(i);
destructure(pattern, type);
}
if (variadic) {
Type tail = unit.getTailType(sequenceType, fixedLength);
destructure(lastPattern, tail);
}
for (int i = types.size(); i < length; i++) {
Tree.Pattern pattern = patterns.get(i);
Node errNode;
if (pattern instanceof Tree.VariablePattern) {
Tree.VariablePattern vp = (Tree.VariablePattern) pattern;
errNode = vp.getVariable();
} else {
errNode = pattern;
}
errNode.addError("assigned tuple has too few elements");
}
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Node in project ceylon by eclipse.
the class ExpressionVisitor method checkTypeArgumentAgainstDeclaration.
private boolean checkTypeArgumentAgainstDeclaration(Type receiver, Declaration dec, List<Type> typeArguments, Tree.TypeArguments tas, Node parent) {
List<TypeParameter> params = dec.getTypeParameters();
boolean explicit = tas instanceof Tree.TypeArgumentList;
int min = 0;
for (TypeParameter tp : params) {
if (!tp.isDefaulted())
min++;
}
if (receiver == null && dec.isClassOrInterfaceMember()) {
receiver = parent.getScope().getDeclaringType(dec);
}
boolean enforceConstraints = modelLiteral || !(parent instanceof Tree.SimpleType) || ((Tree.SimpleType) parent).getInherited();
int max = params.size();
int args = typeArguments.size();
if (args <= max && args >= min) {
for (int i = 0; i < args; i++) {
TypeParameter param = params.get(i);
Type argType = typeArguments.get(i);
boolean argTypeMeaningful = argType != null && !argType.isUnknown();
if (argTypeMeaningful) {
/*if (argType.isTypeConstructor() &&
!param.isTypeConstructor()) {
typeArgNode(tas, i, parent)
.addError("type argument must be a regular type: parameter '" +
param.getName() +
"' is a regular type parameter but '" +
argType.asString(unit) +
"' is a type constructor");
}
else*/
if (enforceConstraints && argType.isTypeParameter()) {
TypeParameter tp = (TypeParameter) argType.getDeclaration();
if (!tp.isReified() && param.isReified()) {
if (explicit) {
typeArgNode(tas, i, parent).addError("type parameter '" + param.getName() + "' of declaration '" + dec.getName(unit) + "' has argument '" + tp.getName() + "' which is not a reified type");
} else {
parent.addError("inferred type argument '" + tp.getName() + "' to type parameter '" + param.getName() + "' of declaration '" + dec.getName(unit) + "' is not a reified type");
}
}
}
if (!argType.isTypeConstructor() && param.isTypeConstructor()) {
typeArgNode(tas, i, parent).addError("type argument must be a type constructor: parameter '" + param.getName() + "' is a type constructor parameter but '" + argType.asString(unit) + "' is a regular type");
} else if (param.isTypeConstructor()) {
Node argNode;
if (explicit) {
Tree.TypeArgumentList tl = (Tree.TypeArgumentList) tas;
argNode = tl.getTypes().get(i);
} else {
argNode = parent;
}
checkTypeConstructorParam(param, argType, argNode);
}
}
List<Type> sts = param.getSatisfiedTypes();
boolean hasConstraints = !sts.isEmpty() || param.getCaseTypes() != null;
if (// !isCondition &&
hasConstraints && enforceConstraints) {
Type assignedType = argumentTypeForBoundsCheck(param, argType);
for (Type st : sts) {
Type bound = st.appliedType(receiver, dec, typeArguments, null);
if (!assignedType.isSubtypeOf(bound)) {
if (argTypeMeaningful) {
if (explicit) {
typeArgNode(tas, i, parent).addError("type parameter '" + param.getName() + "' of declaration '" + dec.getName(unit) + "' has argument '" + assignedType.asString(unit) + "' which is not assignable to upper bound '" + bound.asString(unit) + "' of '" + param.getName() + "'", 2102);
} else {
parent.addError("inferred type argument '" + assignedType.asString(unit) + "' to type parameter '" + param.getName() + "' of declaration '" + dec.getName(unit) + "' is not assignable to upper bound '" + bound.asString(unit) + "' of '" + param.getName() + "'");
}
}
return false;
}
}
if (!argumentSatisfiesEnumeratedConstraint(receiver, dec, typeArguments, assignedType, param)) {
if (argTypeMeaningful) {
if (explicit) {
typeArgNode(tas, i, parent).addError("type parameter '" + param.getName() + "' of declaration '" + dec.getName(unit) + "' has argument '" + assignedType.asString(unit) + "' which is not one of the enumerated cases of '" + param.getName() + "'");
} else {
parent.addError("inferred type argument '" + assignedType.asString(unit) + "' to type parameter '" + param.getName() + "' of declaration '" + dec.getName(unit) + "' is not one of the enumerated cases of '" + param.getName() + "'");
}
}
return false;
}
}
}
return true;
} else {
if (explicit) {
StringBuilder paramList = typeParameterList(dec);
String help;
if (args < min) {
help = " requires at least " + min + " type arguments to " + paramList;
} else if (args > max) {
help = " allows at most " + max + " type arguments to " + paramList;
} else {
help = "";
}
tas.addError("wrong number of type arguments: '" + dec.getName(unit) + "'" + help);
} else {
// Now handled in TypeArgumentVisitor
// if (!metamodel) {
// parent.addError("missing type arguments to generic type: '" +
// dec.getName(unit) +
// "' declares type parameters");
// }
}
return false;
}
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Node in project ceylon by eclipse.
the class ExpressionVisitor method visit.
@Override
public void visit(Tree.MethodArgument that) {
Tree.SpecifierExpression se = that.getSpecifierExpression();
Function fun = that.getDeclarationModel();
Tree.Type type = that.getType();
if (se == null) {
Declaration od = beginReturnDeclaration(fun);
Tree.Type rt = beginReturnScope(type);
super.visit(that);
endReturnScope(rt, fun);
endReturnDeclaration(od);
} else {
super.visit(that);
Tree.Expression e = se.getExpression();
if (e != null) {
inferFunctionType(that, e);
if (type != null && !(type instanceof Tree.DynamicModifier)) {
checkFunctionType(e, type, se);
}
if (fun.isDeclaredVoid() && !isSatementExpression(e)) {
se.addError("functional argument is declared void so specified expression must be a statement: '" + fun.getName() + "' is declared 'void'");
}
}
}
if (type instanceof Tree.LocalModifier) {
if (isTypeUnknown(type.getTypeModel())) {
if (se == null || hasError(type)) {
Node node = type.getToken() == null ? that : type;
node.addError("argument type could not be inferred");
}
}
}
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Node in project ceylon by eclipse.
the class ExpressionVisitor method visit.
@Override
public void visit(Tree.Resource that) {
super.visit(that);
Type t = null;
Node typedNode = null;
Tree.Expression e = that.getExpression();
Tree.Variable v = that.getVariable();
if (e != null) {
t = e.getTypeModel();
typedNode = e;
} else if (v != null) {
t = v.getType().getTypeModel();
typedNode = v.getType();
Tree.SpecifierExpression se = v.getSpecifierExpression();
if (se == null) {
v.addError("missing resource specifier");
} else {
e = se.getExpression();
if (typedNode instanceof Tree.ValueModifier) {
typedNode = se.getExpression();
}
}
} else {
that.addError("missing resource expression");
}
if (typedNode != null) {
if (!isTypeUnknown(t)) {
if (e != null) {
Type ot = unit.getObtainableType();
Type dt = unit.getDestroyableType();
Type act = unit.getJavaAutoCloseableType();
if (!t.isSubtypeOf(act)) {
if (isInstantiationExpression(e)) {
if (!t.isSubtypeOf(dt) && !t.isSubtypeOf(ot)) {
typedNode.addError("resource must be either obtainable or destroyable: '" + t.asString(unit) + "' is neither 'Obtainable' nor 'Destroyable'");
}
} else {
checkAssignable(t, ot, typedNode, "resource must be obtainable");
}
}
}
}
}
}
Aggregations