Package com.redhat.ceylon.compiler.typechecker.analyzer

Source Code of com.redhat.ceylon.compiler.typechecker.analyzer.ArgErrorVisitor

package com.redhat.ceylon.compiler.typechecker.analyzer;

import static com.redhat.ceylon.compiler.typechecker.model.Util.intersectionType;
import static com.redhat.ceylon.compiler.typechecker.model.Util.isTypeUnknown;
import static com.redhat.ceylon.compiler.typechecker.model.Util.producedType;
import static com.redhat.ceylon.compiler.typechecker.model.Util.unionType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.redhat.ceylon.compiler.typechecker.model.Annotation;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Interface;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
import com.redhat.ceylon.compiler.typechecker.model.ProducedReference;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Scope;
import com.redhat.ceylon.compiler.typechecker.model.TypeAlias;
import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.TypeParameter;
import com.redhat.ceylon.compiler.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.model.Value;
import com.redhat.ceylon.compiler.typechecker.tree.Message;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;

/**
* Bucket for some helper methods used by various
* visitors.
*
* @author Gavin King
*
*/
public class Util {
   
    static TypedDeclaration getTypedMember(TypeDeclaration d, String name,
            List<ProducedType> signature, boolean ellipsis, Unit unit) {
        Declaration member = d.getMember(name, unit, signature, ellipsis);
        if (member instanceof TypedDeclaration)
            return (TypedDeclaration) member;
        else
            return null;
    }

    static TypeDeclaration getTypeMember(TypeDeclaration d, String name,
            List<ProducedType> signature, boolean ellipsis, Unit unit) {
        Declaration member = d.getMember(name, unit, signature, ellipsis);
        if (member instanceof TypeDeclaration)
            return (TypeDeclaration) member;
        else
            return null;
    }

    static TypedDeclaration getTypedDeclaration(Scope scope,
            String name, List<ProducedType> signature, boolean ellipsis,
            Unit unit) {
        Declaration result = scope.getMemberOrParameter(unit,
                name, signature, ellipsis);
        if (result instanceof TypedDeclaration) {
          return (TypedDeclaration) result;
        }
        else {
          return null;
        }
    }
   
    static TypeDeclaration getTypeDeclaration(Scope scope,
            String name, List<ProducedType> signature, boolean ellipsis,
            Unit unit) {
        Declaration result = scope.getMemberOrParameter(unit,
                name, signature, ellipsis);
        if (result instanceof TypeDeclaration) {
          return (TypeDeclaration) result;
        }
        else {
          return null;
        }
    }
   
    static List<ProducedType> getTypeArguments(Tree.TypeArguments tal,
        List<TypeParameter> typeParameters, ProducedType qt) {
        if (tal instanceof Tree.TypeArgumentList) {
            List<ProducedType> typeArguments =
                    new ArrayList<ProducedType>(typeParameters.size());
            Map<TypeParameter, ProducedType> typeArgMap =
                    new HashMap<TypeParameter, ProducedType>();
            if (qt!=null) {
                typeArgMap.putAll(qt.getTypeArguments());
            }
            if (tal instanceof Tree.TypeArgumentList) {
                List<Tree.Type> types = ((Tree.TypeArgumentList) tal).getTypes();
                for (int i=0; i<types.size(); i++) {
                    ProducedType t = types.get(i).getTypeModel();
                    if (t==null) {
                        typeArguments.add(null);
                    }
                    else {
                        typeArguments.add(t);
                        if (i<typeParameters.size()) {
                            typeArgMap.put(typeParameters.get(i), t);
                        }
                    }
                }
            }
            else {
                for (int i=0; i<tal.getTypeModels().size(); i++) {
                    ProducedType t = tal.getTypeModels().get(i);
                    if (t==null) {
                        typeArguments.add(null);
                    }
                    else {
                        typeArguments.add(t);
                        if (i<typeParameters.size()) {
                            typeArgMap.put(typeParameters.get(i), t);
                        }
                    }
                }
            }
            for (int i=typeArguments.size();
                i<typeParameters.size(); i++) {
                TypeParameter tp = typeParameters.get(i);
              ProducedType dta = tp.getDefaultTypeArgument();
              if (dta==null ||
                      //necessary to prevent stack overflow
                      //for illegal recursively-defined
                      //default type argument
                      dta.containsDeclaration(tp.getDeclaration())) {
                break;
              }
              else {
                  ProducedType da = dta.substitute(typeArgMap);
                typeArguments.add(da);
                typeArgMap.put(tp, da);
              }
            }
            return typeArguments;
        }
        else {
            return Collections.<ProducedType>emptyList();
        }
    }
   
    /*static List<ProducedType> getParameterTypes(Tree.ParameterTypes pts) {
        if (pts==null) return null;
        List<ProducedType> typeArguments = new ArrayList<ProducedType>();
        for (Tree.SimpleType st: pts.getSimpleTypes()) {
            ProducedType t = st.getTypeModel();
            if (t==null) {
                st.addError("could not resolve parameter type");
                typeArguments.add(null);
            }
            else {
                typeArguments.add(t);
            }
        }
        return typeArguments;
    }*/
   
    public static Tree.Statement getLastExecutableStatement(Tree.ClassBody that) {
        List<Tree.Statement> statements = that.getStatements();
        Unit unit = that.getUnit();
        for (int i=statements.size()-1; i>=0; i--) {
            Tree.Statement s = statements.get(i);
            if (isExecutableStatement(unit, s)) {
                return s;
            }
        }
        return null;
    }

    static boolean isExecutableStatement(Unit unit, Tree.Statement s) {
        if (s instanceof Tree.SpecifierStatement) {
            //shortcut refinement statements with => aren't really "executable"
            Tree.SpecifierStatement ss = (Tree.SpecifierStatement) s;
            return !(ss.getSpecifierExpression()
                    instanceof Tree.LazySpecifierExpression) ||
                    !ss.getRefinement();
        }
        else if (s instanceof Tree.ExecutableStatement) {
            return true;
        }
        else {
            if (s instanceof Tree.AttributeDeclaration) {
                Tree.SpecifierOrInitializerExpression sie =
                        ((Tree.AttributeDeclaration) s).getSpecifierOrInitializerExpression();
            return sie!=null &&
                    !(sie instanceof Tree.LazySpecifierExpression);
            }
            /*else if (s instanceof Tree.MethodDeclaration) {
                if ( ((Tree.MethodDeclaration) s).getSpecifierExpression()!=null ) {
                    return s;
                }
            }*/
            else if (s instanceof Tree.ObjectDefinition) {
                Tree.ObjectDefinition o = (Tree.ObjectDefinition) s;
                if (o.getExtendedType()!=null) {
                    ProducedType et = o.getExtendedType().getType().getTypeModel();
              if (et!=null
                            && !et.getDeclaration().equals(unit.getObjectDeclaration())
                            && !et.getDeclaration().equals(unit.getBasicDeclaration())) {
                        return true;
                    }
                }
                if (o.getClassBody()!=null) {
                    if (getLastExecutableStatement(o.getClassBody())!=null) {
                        return true;
                    }
                }
                return false;
            }
            else {
                return false;
            }
        }
    }
   
    private static String message(ProducedType type, String problem,
            ProducedType otherType, Unit unit) {
        String typeName = type.getProducedTypeName(unit);
        String otherTypeName = otherType.getProducedTypeName(unit);
        if (otherTypeName.equals(typeName)) {
            typeName = type.getProducedTypeQualifiedName();
            otherTypeName = otherType.getProducedTypeQualifiedName();
        }
        return ": '" + typeName + "'" + problem + "'" + otherTypeName + "'";
    }
   
    private static String message(ProducedType type, String problem, Unit unit) {
        String typeName = type.getProducedTypeName(unit);
        return ": '" + typeName + "'" + problem;
    }
   
    static boolean checkCallable(ProducedType type, Node node, String message) {
        Unit unit = node.getUnit();
        if (isTypeUnknown(type)) {
            addTypeUnknownError(node, message);
            return false;
        }
        else if (!unit.isCallableType(type)) {
            if (!hasError(node)) {
                String extra = message(type,
                        " is not a subtype of 'Callable'", unit);
                if (node instanceof Tree.StaticMemberOrTypeExpression) {
                    Declaration d =
                            ((Tree.StaticMemberOrTypeExpression) node).getDeclaration();
                    if (d instanceof Interface) {
                        extra = ": '" + d.getName() + "' is an interface";
                    }
                    else if (d instanceof TypeAlias) {
                        extra = ": '" + d.getName() + "' is a type alias";
                    }
                    else if (d instanceof TypeParameter) {
                        extra = ": '" + d.getName() + "' is a type parameter";
                    }
                    else if (d instanceof Value) {
                        extra = ": value '" + d.getName() + "' has type '" +
                                type.getProducedTypeName(unit) +
                                "' which is not a subtype of 'Callable'";
                    }
                }
                node.addError(message + extra);
            }
            return false;
        }
        else {
            return true;
        }
    }

    static ProducedType checkSupertype(ProducedType pt, TypeDeclaration td,
            Node node, String message) {
        if (isTypeUnknown(pt)) {
            addTypeUnknownError(node, message);
            return null;
        }
        else {
            ProducedType supertype = pt.getSupertype(td);
            if (supertype==null) {
                node.addError(message +
                        message(pt, " is not a subtype of '" + td.getName() + "'",
                    node.getUnit()));
            }
            return supertype;
        }
    }

    static void checkAssignable(ProducedType type, ProducedType supertype,
            Node node, String message) {
        if (isTypeUnknown(type) || isTypeUnknown(supertype)) {
          addTypeUnknownError(node, message);
        }
        else if (!type.isSubtypeOf(supertype)) {
          node.addError(message +
                  message(type, " is not assignable to ",
                          supertype, node.getUnit()));
        }
    }

    static void checkAssignableWithWarning(ProducedType type,
            ProducedType supertype, Node node, String message) {
        if (isTypeUnknown(type) || isTypeUnknown(supertype)) {
          addTypeUnknownError(node, message);
        }
        else if (!type.isSubtypeOf(supertype)) {
          node.addUnsupportedError(message +
                  message(type, " is not assignable to ",
                          supertype, node.getUnit()));
        }
    }

    static void checkAssignableToOneOf(ProducedType type,
        ProducedType supertype1, ProducedType supertype2,
            Node node, String message) {
        if (isTypeUnknown(type) ||
            isTypeUnknown(supertype1) || isTypeUnknown(supertype2)) {
            addTypeUnknownError(node, message);
        }
        else if (!type.isSubtypeOf(supertype1)
                && !type.isSubtypeOf(supertype2)) {
            node.addError(message +
                    message(type, " is not assignable to ",
                            supertype1, node.getUnit()));
        }
    }

    static void checkAssignable(ProducedType type, ProducedType supertype,
            Node node, String message, int code) {
        if (isTypeUnknown(type) || isTypeUnknown(supertype)) {
            addTypeUnknownError(node, message);
        }
        else if (!type.isSubtypeOf(supertype)) {
            node.addError(message +
                    message(type, " is not assignable to ",
                            supertype, node.getUnit()), code);
        }
    }

    /*static void checkAssignable(ProducedType type, ProducedType supertype,
            TypeDeclaration td, Node node, String message) {
        if (isTypeUnknown(type) || isTypeUnknown(supertype)) {
            addTypeUnknownError(node, message);
        }
        else if (!type.isSubtypeOf(supertype)) {
            node.addError(message + message(type, " is not assignable to ", supertype, node.getUnit()));
        }
    }*/

    static void checkIsExactly(ProducedType type, ProducedType supertype,
            Node node, String message) {
        if (isTypeUnknown(type) || isTypeUnknown(supertype)) {
            addTypeUnknownError(node, message);
        }
        else if (!type.isExactly(supertype)) {
            node.addError(message + message(type, " is not exactly ",
                supertype, node.getUnit()));
        }
    }

    static void checkIsExactly(ProducedType type, ProducedType supertype,
            Node node, String message, int code) {
        if (isTypeUnknown(type) || isTypeUnknown(supertype)) {
            addTypeUnknownError(node, message);
        }
        else if (!type.isExactly(supertype)) {
            node.addError(message + message(type, " is not exactly ",
                supertype, node.getUnit()), code);
        }
    }

    static void checkIsExactlyOneOf(ProducedType type,
        ProducedType supertype1, ProducedType supertype2,
            Node node, String message) {
        if (isTypeUnknown(type) ||
            isTypeUnknown(supertype1) || isTypeUnknown(supertype2)) {
            addTypeUnknownError(node, message);
        }
        else if (!type.isExactly(supertype1)
                && !type.isExactly(supertype2)) {
            node.addError(message + message(type, " is not exactly ",
                supertype1, node.getUnit()));
        }
    }
   
    public static boolean hasErrorOrWarning(Node node) {
        return hasError(node, true);
    }

    public static boolean hasError(Node node) {
        return hasError(node, false);
    }

    static boolean hasError(Node node,
            final boolean includeWarnings) {
        // we use an exception to get out of the visitor
        // as fast as possible when an error is found
        // TODO: wtf?! because it's the common case that
        //       a node has an error? that's just silly
        @SuppressWarnings("serial")
        class ErrorFoundException extends RuntimeException {}
        class ErrorVisitor extends Visitor {
            @Override
            public void handleException(Exception e, Node that) {
                if (e instanceof ErrorFoundException) {
                    throw (ErrorFoundException) e;
                }
                super.handleException(e, that);
            }
            @Override
            public void visitAny(Node that) {
                if (that.getErrors().isEmpty()) {
                    super.visitAny(that);
                }
                else if (includeWarnings) {
                    throw new ErrorFoundException();
                }
                else {
                    // UsageWarning don't count as errors
                    for (Message error: that.getErrors()) {
                        if (!(error instanceof UsageWarning)) {
                            // get out fast
                            throw new ErrorFoundException();
                        }
                    }
                    // no real error, proceed
                    super.visitAny(that);
                }
            }
        }
        ErrorVisitor ev = new ErrorVisitor();
        try {
            node.visit(ev);
            return false;
        }
        catch (ErrorFoundException x) {
            return true;
        }
    }

    private static void addTypeUnknownError(Node node, String message) {
        if (!hasError(node)) {
            node.addError(message + ": type cannot be determined");
        }
    }

    public static void buildAnnotations(Tree.AnnotationList al,
            List<Annotation> annotations) {
        if (al!=null) {
            Tree.AnonymousAnnotation aa = al.getAnonymousAnnotation();
            if (aa!=null) {
                Annotation ann = new Annotation();
                ann.setName("doc");
                ann.addPositionalArgment(aa.getStringLiteral().getText());
                annotations.add(ann);
            }
            for (Tree.Annotation a: al.getAnnotations()) {
                Annotation ann = new Annotation();
                String name = ((Tree.BaseMemberExpression)
                        a.getPrimary()).getIdentifier().getText();
                ann.setName(name);
                if (a.getNamedArgumentList()!=null) {
                    for (Tree.NamedArgument na:
                            a.getNamedArgumentList().getNamedArguments()) {
                        if (na instanceof Tree.SpecifiedArgument) {
                            Tree.SpecifierExpression sie =
                                    ((Tree.SpecifiedArgument) na).getSpecifierExpression();
                            Tree.Expression e = sie.getExpression();
                            if (e!=null) {
                                Tree.Term t = e.getTerm();
                                Parameter p =
                                        ((Tree.SpecifiedArgument) na).getParameter();
                                if (p!=null) {
                                    String text = toString(t);
                                    if (text!=null) {
                                        ann.addNamedArgument(p.getName(), text);
                                    }
                                }
                            }
                        }                   
                    }
                }
                if (a.getPositionalArgumentList()!=null) {
                    for (Tree.PositionalArgument pa:
                            a.getPositionalArgumentList().getPositionalArguments()) {
                      if (pa instanceof Tree.ListedArgument) {
                        Tree.Term t =
                                ((Tree.ListedArgument) pa).getExpression().getTerm();
                        String text = toString(t);
                        if (text!=null) {
                          ann.addPositionalArgment(text);
                        }
                      }
                    }
                }
                annotations.add(ann);
            }
        }
    }
   
    private static String toString(Tree.Term t) {
      if (t instanceof Tree.Literal) {
        return ((Tree.Literal) t).getText();
      }
      else if (t instanceof Tree.StaticMemberOrTypeExpression) {
        Tree.StaticMemberOrTypeExpression mte = (Tree.StaticMemberOrTypeExpression) t;
        String id = mte.getIdentifier().getText();
        if (mte instanceof Tree.QualifiedMemberOrTypeExpression) {
          Tree.Primary p = ((Tree.QualifiedMemberOrTypeExpression) mte).getPrimary();
          if (p instanceof Tree.StaticMemberOrTypeExpression) {
            return toString((Tree.StaticMemberOrTypeExpression) p) + '.' + id;
          }
          return null;
        }
        else {
          return id;
        }
      }
      else if (t instanceof Tree.TypeLiteral) {
          Tree.TypeLiteral tl = (Tree.TypeLiteral) t;
          if(tl.getType() != null)
              return toString(tl.getType());
          return null;
      }
        else if (t instanceof Tree.MemberLiteral) {
            Tree.MemberLiteral ml = (Tree.MemberLiteral) t;
            if(ml.getType() != null){
                String qualifier = toString(ml.getType());
                if(qualifier != null && ml.getIdentifier()!=null)
                    return qualifier + "." + ml.getIdentifier().getText();
                return null;
            }
            return ml.getIdentifier().getText();
        }
      else {
        return null;
      }
    }

    private static String toString(Tree.StaticType type) {
        // FIXME: we're discarding syntactic types and union/intersection types
        if(type instanceof Tree.BaseType){
            return ((Tree.BaseType) type).getIdentifier().getText();
        }else if(type instanceof Tree.QualifiedType){
            String qualifier = toString(((Tree.QualifiedType) type).getOuterType());
            if(qualifier != null)
                return qualifier + "." + ((Tree.SimpleType)type).getIdentifier().getText();
            return null;
        }
        return null;
    }

    static boolean inLanguageModule(Unit unit) {
        return unit.getPackage().getQualifiedNameString()
                .startsWith(Module.LANGUAGE_MODULE_NAME);
    }

    static String typeDescription(TypeDeclaration td, Unit unit) {
        if (td instanceof TypeParameter) {
            Declaration container = (Declaration) td.getContainer();
            return "type parameter '" + td.getName() + "' of '" +
                    container.getName(unit) + "'";
        }
        else {
            return "type '" + td.getName() + "'";
        }
    }

    static String typeNamesAsIntersection(
            List<ProducedType> upperBounds, Unit unit) {
        if (upperBounds.isEmpty()) {
            return "Anything";
        }
        StringBuilder sb = new StringBuilder();
        for (ProducedType st: upperBounds) {
            sb.append(st.getProducedTypeName(unit)).append(" & ");
        }
        if (sb.toString().endsWith(" & ")) {
            sb.setLength(sb.length()-3);
        }
        return sb.toString();
    }

    public static Tree.Term eliminateParensAndWidening(Tree.Term term) {
        while (term instanceof Tree.OfOp ||
               term instanceof Tree.Expression) {
            if (term instanceof Tree.OfOp) {
                term = ((Tree.OfOp) term).getTerm();
            }
            else if (term instanceof Tree.Expression) {
                term = ((Tree.Expression) term).getTerm();
            }
        }
        return term;
    }

    static boolean isAlwaysSatisfied(Tree.ConditionList cl) {
        if (cl==null) return false;
        for (Tree.Condition c: cl.getConditions()) {
            if (c instanceof Tree.BooleanCondition) {
                Tree.Expression ex = ((Tree.BooleanCondition) c).getExpression();
                if (ex!=null) {
                    Tree.Term t = ex.getTerm();
                    //TODO: eliminate parens
                    //TODO: take into account conjunctions/disjunctions
                    if (t instanceof Tree.BaseMemberExpression) {
                        Declaration d = ((Tree.BaseMemberExpression) t).getDeclaration();
                        if (isBooleanTrue(d)) {
                            continue;
                        }
                    }
                }
            }
            return false;
        }
        return true;
    }

    public static boolean isBooleanTrue(Declaration d) {
        return d!=null && d.getQualifiedNameString()
                .equals("ceylon.language::true");
    }

    public static boolean isBooleanFalse(Declaration d) {
        return d!=null && d.getQualifiedNameString()
                .equals("ceylon.language::false");
    }

    static boolean isNeverSatisfied(Tree.ConditionList cl) {
        if (cl==null) return false;
        for (Tree.Condition c: cl.getConditions()) {
            if (c instanceof Tree.BooleanCondition) {
                Tree.Expression ex = ((Tree.BooleanCondition) c).getExpression();
                if (ex!=null) {
                    Tree.Term t = ex.getTerm();
                    //TODO: eliminate parens
                    //TODO: take into account conjunctions/disjunctions
                    if (t instanceof Tree.BaseMemberExpression) {
                        Declaration d = ((Tree.BaseMemberExpression) t).getDeclaration();
                        if (isBooleanFalse(d)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
   
    static boolean isAtLeastOne(Tree.ForClause forClause) {
        Tree.ForIterator fi = forClause.getForIterator();
        if (fi!=null) {
            Tree.SpecifierExpression se = fi.getSpecifierExpression();
            if (se!=null) {
                Tree.Expression e = se.getExpression();
                if (e!=null) {
                    Unit unit = forClause.getUnit();
                    ProducedType at =
                            unit.getAnythingDeclaration().getType();
                    ProducedType neit = unit.getNonemptyIterableType(at);
                    ProducedType t = e.getTypeModel();
                    return t!=null && t.isSubtypeOf(neit);
                }
            }
        }
        return false;
    }

    static boolean declaredInPackage(Declaration dec, Unit unit) {
        return dec.getUnit().getPackage().equals(unit.getPackage());
    }

    public static Tree.Term unwrapExpressionUntilTerm(Tree.Term term){
        while (term instanceof Tree.Expression) {
            term = ((Tree.Expression)term).getTerm();
        }
        return term;
    }
   
    public static boolean isIndirectInvocation(Tree.InvocationExpression that) {
        Tree.Term p = unwrapExpressionUntilTerm(that.getPrimary());
        if (p instanceof Tree.MemberOrTypeExpression) {
            Tree.MemberOrTypeExpression mte = (Tree.MemberOrTypeExpression) p;
            ProducedReference prf = mte.getTarget();
            return mte.getStaticMethodReference() ||
                    prf==null ||
                    !prf.isFunctional() ||
                    //type parameters are not really callable even though they are Functional
                    prf.getDeclaration() instanceof TypeParameter;
        }
        else {
           return true;
        }
    }
   
    public static boolean isInstantiationExpression(Tree.Expression e) {
        Tree.Term term = e.getTerm();
        if (term instanceof Tree.InvocationExpression) {
            Tree.InvocationExpression ie = (Tree.InvocationExpression) term;
            Tree.Primary p = ie.getPrimary();
            if (p instanceof Tree.BaseTypeExpression ||
                p instanceof Tree.QualifiedTypeExpression) {
                return true;
            }
        }
        return false;
    }
   
    public static boolean hasErrors(Tree.Declaration d) {
        class DeclarationErrorVisitor extends Visitor {
            boolean foundError;
            @Override
            public void visitAny(Node that) {
                super.visitAny(that);
                if (!that.getErrors().isEmpty()) {
                    foundError = true;
                }
            }
            @Override
            public void visit(Tree.Body that) {}
        }
        DeclarationErrorVisitor dev = new DeclarationErrorVisitor();
        d.visit(dev);
        return dev.foundError;
    }

    public static boolean hasErrors(Tree.TypedArgument d) {
        class ArgErrorVisitor extends Visitor {
            boolean foundError;
            @Override
            public void visitAny(Node that) {
                super.visitAny(that);
                if (!that.getErrors().isEmpty()) {
                    foundError = true;
                }
            }
            @Override
            public void visit(Tree.Body that) {}
        }
        ArgErrorVisitor dev = new ArgErrorVisitor();
        d.visit(dev);
        return dev.foundError;
    }

    public static boolean hasErrors(Tree.Body d) {
        class BodyErrorVisitor extends Visitor {
            boolean foundError;
            @Override
            public void visitAny(Node that) {
                super.visitAny(that);
                if (!that.getErrors().isEmpty()) {
                    foundError = true;
                }
            }
            @Override
            public void visit(Tree.Declaration that) {}
        }
        BodyErrorVisitor bev = new BodyErrorVisitor();
        d.visit(bev);
        return bev.foundError;
    }

    static String message(Declaration refined) {
        String container;
        if (refined.getContainer() instanceof Declaration) {
            String name = ((Declaration) refined.getContainer()).getName();
            container = " in '" + name + "'";
        }
        else {
            container = "";
        }
        return "'" + refined.getName() + "'" + container;
    }
   
    public static Node getParameterTypeErrorNode(Tree.Parameter p) {
        if (p instanceof Tree.ParameterDeclaration) {
            return ((Tree.ParameterDeclaration) p).getTypedDeclaration().getType();
        }
        else {
            return p;
        }
    }
   
    public static Node getTypeErrorNode(Node that) {
        if (that instanceof Tree.TypedDeclaration) {
            Tree.Type type = ((Tree.TypedDeclaration) that).getType();
            if (type!=null) {
                return type;
            }
        }
        if (that instanceof Tree.TypedArgument) {
            Tree.Type type = ((Tree.TypedArgument) that).getType();
            if (type!=null) {
                return type;
            }
        }
        if (that instanceof Tree.FunctionArgument) {
            Tree.Type type = ((Tree.FunctionArgument) that).getType();
            if (type!=null && type.getToken()!=null) {
                return type;
            }
        }
        return that;
    }

    static void checkIsExactlyForInterop(Unit unit, boolean isCeylon, 
            ProducedType parameterType, ProducedType refinedParameterType, Node node,
            String message) {
        if (isCeylon) {
            // it must be a Ceylon method
            checkIsExactly(parameterType, refinedParameterType, node, message, 9200);
        }
        else {
            // we're refining a Java method
            ProducedType refinedDefiniteType = unit.getDefiniteType(refinedParameterType);
            checkIsExactlyOneOf(parameterType, refinedParameterType, refinedDefiniteType,
                node, message);
        }
    }

    public static ProducedType getTupleType(List<Tree.PositionalArgument> es, Unit unit,
            boolean requireSequential) {
        ProducedType result = unit.getType(unit.getEmptyDeclaration());
        ProducedType ut = unit.getNothingDeclaration().getType();
        for (int i=es.size()-1; i>=0; i--) {
            Tree.PositionalArgument a = es.get(i);
            ProducedType t = a.getTypeModel();
            if (t!=null) {
                ProducedType et = unit.denotableType(t);
                if (a instanceof Tree.SpreadArgument) {
                    /*if (requireSequential) {
                        checkSpreadArgumentSequential((Tree.SpreadArgument) a, et);
                    }*/
                    ut = unit.getIteratedType(et);
                    result = spreadType(et, unit, requireSequential);
                }
                else if (a instanceof Tree.Comprehension) {
                    ut = et;
                    Tree.InitialComprehensionClause icc = ((Tree.Comprehension) a).getInitialComprehensionClause();
                    result = icc.getPossiblyEmpty() ?
                            unit.getSequentialType(et) :
                            unit.getSequenceType(et);
                    if (!requireSequential) {
                        ProducedType it = producedType(unit.getIterableDeclaration(),
                                et, icc.getFirstTypeModel());
                        result = intersectionType(result, it, unit);
                    }
                }
                else {
                    ut = unionType(ut, et, unit);
                    result = producedType(unit.getTupleDeclaration(), ut, et, result);
                }
            }
        }
        return result;
    }
   
    public static ProducedType spreadType(ProducedType et, Unit unit,
            boolean requireSequential) {
        if (et==null) return null;
        if (requireSequential) {
            if (unit.isSequentialType(et)) {
                //if (et.getDeclaration() instanceof TypeParameter) {
                    return et;
                /*}
                else {
                    // if it's already a subtype of Sequential, erase
                    // out extraneous information, like that it is a
                    // String, just keeping information about what
                    // kind of tuple it is
                    List<ProducedType> elementTypes = unit.getTupleElementTypes(et);
                    boolean variadic = unit.isTupleLengthUnbounded(et);
                    boolean atLeastOne = unit.isTupleVariantAtLeastOne(et);
                    int minimumLength = unit.getTupleMinimumLength(et);
                    if (variadic) {
                        ProducedType spt = elementTypes.get(elementTypes.size()-1);
                        elementTypes.set(elementTypes.size()-1, unit.getIteratedType(spt));
                    }
                    return unit.getTupleType(elementTypes, variadic,
                            atLeastOne, minimumLength);
                }*/
            }
            else {
                // transform any Iterable into a Sequence without
                // losing the information that it is nonempty, in
                // the case that we know that for sure
                ProducedType st = unit.isNonemptyIterableType(et) ?
                        unit.getSequenceType(unit.getIteratedType(et)) :
                        unit.getSequentialType(unit.getIteratedType(et));
                // unless this is a tuple constructor, remember
                // the original Iterable type arguments, to
                // account for the possibility that the argument
                // to Absent is a type parameter
                //return intersectionType(et.getSupertype(unit.getIterableDeclaration()), st, unit);
                // for now, just return the sequential type:
                return st;
            }
        }
        else {
            return et;
        }
    }

    static boolean isSelfReference(Tree.Primary that) {
        return that instanceof Tree.This ||
                that instanceof Tree.Outer;
    }

    static boolean isEffectivelyBaseMemberExpression(Tree.Term term) {
        return term instanceof Tree.BaseMemberExpression ||
                term instanceof Tree.QualifiedMemberExpression &&
                isSelfReference(((Tree.QualifiedMemberExpression) term).getPrimary());
    }
}
TOP

Related Classes of com.redhat.ceylon.compiler.typechecker.analyzer.ArgErrorVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.