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

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

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

import static com.redhat.ceylon.compiler.typechecker.analyzer.TypeVisitor.getTupleType;
import static com.redhat.ceylon.compiler.typechecker.analyzer.Util.buildAnnotations;
import static com.redhat.ceylon.compiler.typechecker.analyzer.Util.getTypeDeclaration;
import static com.redhat.ceylon.compiler.typechecker.model.Util.getContainingClassOrInterface;
import static com.redhat.ceylon.compiler.typechecker.model.Util.getTypeArgumentMap;
import static com.redhat.ceylon.compiler.typechecker.model.Util.intersectionOfSupertypes;
import static com.redhat.ceylon.compiler.typechecker.parser.CeylonLexer.SPECIFY;
import static com.redhat.ceylon.compiler.typechecker.tree.Util.formatPath;
import static com.redhat.ceylon.compiler.typechecker.tree.Util.hasAnnotation;
import static com.redhat.ceylon.compiler.typechecker.tree.Util.name;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;

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.Class;
import com.redhat.ceylon.compiler.typechecker.model.ClassAlias;
import com.redhat.ceylon.compiler.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.compiler.typechecker.model.ConditionScope;
import com.redhat.ceylon.compiler.typechecker.model.ControlBlock;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Element;
import com.redhat.ceylon.compiler.typechecker.model.Generic;
import com.redhat.ceylon.compiler.typechecker.model.ImportList;
import com.redhat.ceylon.compiler.typechecker.model.Interface;
import com.redhat.ceylon.compiler.typechecker.model.InterfaceAlias;
import com.redhat.ceylon.compiler.typechecker.model.IntersectionType;
import com.redhat.ceylon.compiler.typechecker.model.LazyProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.NamedArgumentList;
import com.redhat.ceylon.compiler.typechecker.model.Package;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
import com.redhat.ceylon.compiler.typechecker.model.ParameterList;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Scope;
import com.redhat.ceylon.compiler.typechecker.model.Setter;
import com.redhat.ceylon.compiler.typechecker.model.Specification;
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.UnionType;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.model.UnknownType;
import com.redhat.ceylon.compiler.typechecker.model.Value;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.NaturalLiteral;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.TypeParameterDeclaration;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.compiler.typechecker.util.UnitFactory;

/**
* First phase of type analysis.
* Scan a compilation unit searching for declarations,
* and builds up the model objects. At this point, all
* we know is the name of the declaration and what
* kind of declaration it is. The model objects do not
* contain type information.
*
* @author Gavin King
*
*/
public class DeclarationVisitor extends Visitor {
   
    private final Package pkg;
    private final String filename;
    private Scope scope;
    private Unit unit;
    private ParameterList parameterList;
    private Declaration declaration;
    private String fullPath;
    private String relativePath;
    private boolean dynamic;
    protected UnitFactory unitFactory;
   
    public DeclarationVisitor(Package pkg, String filename,
            String fullPath, String relativePath, UnitFactory unitFactory) {
        scope = pkg;
        this.pkg = pkg;
        this.filename = filename;
        this.fullPath = fullPath;
        this.relativePath = relativePath;
        this.unitFactory = unitFactory;
    }

    public Unit getCompilationUnit() {
        return unit;
    }
   
    private Scope enterScope(Scope innerScope) {
        Scope outerScope = scope;
        scope = innerScope;
        return outerScope;
    }

    private void exitScope(Scope outerScope) {
        scope = outerScope;
    }
   
    private Declaration beginDeclaration(Declaration innerDec) {
        Declaration outerDec = declaration;
        declaration = innerDec;
        return outerDec;
    }

    private void endDeclaration(Declaration outerDec) {
        declaration = outerDec;
    }
   
    private void visitDeclaration(Tree.Declaration that, Declaration model) {
        visitDeclaration(that,  model, true);
    }
   
    private void visitDeclaration(Tree.Declaration that, Declaration model, boolean checkDupe) {
        visitElement(that, model);
        if (setModelName(that, model, that.getIdentifier())) {
            if (checkDupe) {
                checkForDuplicateDeclaration(that, model);
            }
        }
        //that.setDeclarationModel(model);
        unit.addDeclaration(model);
        Scope sc = getContainer(that);
        sc.addMember(model);
       
        handleDeclarationAnnotations(that, model);       
       
        setVisibleScope(model);
       
        checkFormalMember(that, model);
    }

    private void visitArgument(Tree.NamedArgument that, Declaration model) {
        Tree.Identifier id = that.getIdentifier();
        setModelName(that, model, id);
        visitElement(that, model);
        //that.setDeclarationModel(model);
        unit.addDeclaration(model);
        setVisibleScope(model);
    }

    private void visitArgument(Tree.FunctionArgument that, Declaration model) {
        visitElement(that, model);
        //that.setDeclarationModel(model);
        unit.addDeclaration(model);
        setVisibleScope(model);
    }

    private static boolean setModelName(Node that, Declaration model,
            Tree.Identifier id) {
        if (id==null || id.isMissingToken()) {
            that.addError("missing declaration name");
            return false;
        }
        else {
            model.setName(id.getText());
            return true;
            //TODO: check for dupe arg name
        }
    }
   
    private static void checkForDuplicateDeclaration(Tree.Declaration that,
            final Declaration model) {
        if (model.getName()!=null) {
            if (model instanceof Setter) {
                Setter setter = (Setter) model;
                //a setter must have a matching getter
                Declaration member =
                        model.getContainer().getDirectMember(model.getName(),
                                null, false);
                if (member==null) {
                    that.addError("setter with no matching getter: '" +
                            model.getName() + "'");
                }
                else if (!(member instanceof Value)) {
                    that.addError("setter name does not resolve to matching getter: '" +
                            model.getName() + "'");
                }
                else if (!((Value) member).isTransient()) {
                    that.addError("matching value is a reference or is forward-declared: '" +
                            model.getName() + "'");
                }
                else {
                    Value getter = (Value) member;
                    setter.setGetter(getter);
                    if (getter.isVariable()) {
                        that.addError("duplicate setter for getter: '" +
                                model.getName() + "'");
                    }
                    else {
                        getter.setSetter(setter);
                    }
                }
            }
            else {
                Scope s = model.getContainer();
                boolean isControl;
                do {
                    Declaration member =
                            s.getDirectMember(model.getName(), null, false);
                    if (member!=null) {
                        Unit unit = model.getUnit();
                        if (member instanceof Method &&
                            model instanceof Method &&
                            s instanceof ClassOrInterface) {
                            Method abstraction;
                            if (!((Method) member).isAbstraction()) {
                                abstraction = new Method();
                                abstraction.setAbstraction(true);
                                abstraction.setType(new UnknownType(unit).getType());
                                abstraction.setName(model.getName());
                                abstraction.setShared(true);
                                abstraction.setActual(true);
                                abstraction.setContainer(s);
                                abstraction.setScope(s);
                                abstraction.setUnit(unit);
                                ((Method) member).setOverloaded(true);
                                abstraction.setOverloads(new ArrayList<Declaration>());
                                abstraction.getOverloads().add(member);
                                s.getMembers().add(abstraction);
                            }
                            else {
                                abstraction = (Method) member;
                            }
                            ((Method) model).setOverloaded(true);
                            abstraction.getOverloads().add(model);
                        }
                        else {
                            that.addError("duplicate declaration name: '" +
                                    model.getName() + "'");
                        }
                        unit.getDuplicateDeclarations().add(member);
                    }
                    isControl = s instanceof ControlBlock;
                    s = s.getContainer();
                }
                while (isControl);
            }
        }
    }

    private void visitElement(Node that, Element model) {
        model.setUnit(unit);
        model.setScope(scope);
        model.setContainer(getContainer(that));
    }

    /**
     * Get the containing scope, skipping any condition
     * scopes.
     *
     * @see com.redhat.ceylon.compiler.typechecker.model.ConditionScope
     */
    private Scope getContainer(Node that) {
        if (that instanceof Tree.Declaration &&
                !(that instanceof Tree.Parameter) &&
                !(that instanceof Tree.Variable)) {
            Scope s = scope;
            while (s instanceof ConditionScope) {
                s = s.getScope();
            }
            return s;
        }
        else {
            return scope;
        }
    }
   
    @Override
    public void visitAny(Node that) {
        that.setScope(scope);
        that.setUnit(unit);
        super.visitAny(that);
    }
   
    @Override
    public void visit(Tree.DynamicStatement that) {
        boolean od = dynamic;
        dynamic = true;
        super.visit(that);
        dynamic = od;
    }
   
    @Override
    public void visit(Tree.CompilationUnit that) {
        unit = unitFactory.createUnit();
        //that.setModelNode(unit);
        unit.setPackage(pkg);
        unit.setFilename(filename);
        unit.setFullPath(fullPath);
        unit.setRelativePath(relativePath);
        pkg.removeUnit(unit);
        pkg.addUnit(unit);
        super.visit(that);
        Node firstNonImportNode = null;
        int index = -1;
        for (Node d: that.getDeclarations()) {
            firstNonImportNode = d;
            index = d.getToken().getTokenIndex();
            break;
        }
        for (Tree.ModuleDescriptor md: that.getModuleDescriptors()) {
            if (index<0 || md.getToken().getTokenIndex()<index) {
                firstNonImportNode = md;
                index = md.getToken().getTokenIndex();
            }
            break;
        }
        for (Tree.PackageDescriptor pd: that.getPackageDescriptors()) {
            if (index<0 || pd.getToken().getTokenIndex()<index) {
                firstNonImportNode = pd;
                index = pd.getToken().getTokenIndex();
            }
            break;
        }
        if (firstNonImportNode!=null) {
            for (Tree.Import im: that.getImportList().getImports()) {
                if (im.getStopIndex()>firstNonImportNode.getStartIndex()) {
                    im.addError("import statement must occur before any declaration or descriptor");
                }
            }
        }
        boolean first=true;
        for (Tree.ModuleDescriptor md: that.getModuleDescriptors()) {
            if (!first) {
                md.addError("there may be only one module descriptor for a module");
            }
            first=false;
        }
        first=true;
        for (Tree.PackageDescriptor pd: that.getPackageDescriptors()) {
            if (!first) {
                pd.addError("there may be only one package descriptor for a module");
            }
            first=false;
        }
    }
   
    @Override
    public void visit(Tree.ImportMemberOrTypeList that) {
        ImportList il = new ImportList();
        unit.getImportLists().add(il);
        that.setImportList(il);
        il.setContainer(scope);
        Scope o = enterScope(il);
        super.visit(that);
        exitScope(o);
    }
   
    @Override
    public void visit(Tree.TypeParameterList that) {
        super.visit(that);
        ((Generic) declaration).setTypeParameters(getTypeParameters(that));
    }   
       
    private void defaultExtendedToBasic(Class c) {
        //default supertype for classes
        c.setExtendedType(new LazyProducedType(unit) {
            @Override
            public Map<TypeParameter, ProducedType> initTypeArguments() {
                return emptyMap();
            }
            @Override
            public TypeDeclaration initDeclaration() {
                return unit.getBasicDeclaration();
            }
        });
    }

    private void defaultExtendedToObject(Interface c) {
        //default supertype for interfaces
        c.setExtendedType(new LazyProducedType(unit) {
            @Override
            public Map<TypeParameter, ProducedType> initTypeArguments() {
                return emptyMap();
            }
            @Override
            public TypeDeclaration initDeclaration() {
                return unit.getObjectDeclaration();
            }
        });
    }

    private void defaultExtendedToAnything(TypeParameter c) {
        //default supertype for interfaces
        c.setExtendedType(new LazyProducedType(unit) {
            @Override
            public Map<TypeParameter, ProducedType> initTypeArguments() {
                return emptyMap();
            }
            @Override
            public TypeDeclaration initDeclaration() {
                return unit.getAnythingDeclaration();
            }
        });
    }
   
    @Override
    public void visit(Tree.ClassDefinition that) {
        Class c = new Class();
        if (!unit.getPackage().getQualifiedNameString().equals("ceylon.language") ||
                !"Anything".equalsIgnoreCase(name(that.getIdentifier()))) {
            defaultExtendedToBasic(c);
        }
        that.setDeclarationModel(c);
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.ClassDeclaration that) {
        Class c = new ClassAlias();
        that.setDeclarationModel(c);
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.AnyClass that) {
        Class c = that.getDeclarationModel();
        visitDeclaration(that, c);
        Scope o = enterScope(c);
        super.visit(that);
        exitScope(o);
        if (that.getParameterList()==null) {
            that.addError("missing parameter list in class declaration: '" +
                    name(that.getIdentifier()) + "' must have a parameter list", 1000);
        }
        else {
            that.getParameterList().getModel().setFirst(true);
            c.addParameterList(that.getParameterList().getModel());
        }
        //TODO: is this still necessary??
        if (c.isClassOrInterfaceMember() &&
                c.getContainer() instanceof TypedDeclaration) {
            that.addUnsupportedError("nested classes of inner classes are not yet supported");
        }
        if (c.isAbstract() && c.isFinal()) {
            that.addError("class may not be both abstract and final: '" +
                    name(that.getIdentifier()) + "'");
        }
        if (c.isFormal() && c.isFinal()) {
            that.addError("class may not be both formal and final: '" +
                    name(that.getIdentifier()) + "'");
        }
    }

    @Override
    public void visit(Tree.InterfaceDefinition that) {
        Interface i = new Interface();
        i.setDynamic(that.getDynamic());
        defaultExtendedToObject(i);
        that.setDeclarationModel(i);
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.InterfaceDeclaration that) {
        InterfaceAlias i = new InterfaceAlias();
        that.setDeclarationModel(i);
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.AnyInterface that) {
        Interface i = that.getDeclarationModel();
        that.setDeclarationModel(i);
        visitDeclaration(that, i);
        Scope o = enterScope(i);
        super.visit(that);
        exitScope(o);
        /*if (!i.isToplevel()) {
            that.addWarning("inner interfaces are not yet supported");
        }*/
        /*if ( that.getCaseTypes()!=null ) {
            that.addWarning("interfaces with enumerated cases not yet supported");
        }*/
    }
   
    @Override
    public void visit(Tree.TypeAliasDeclaration that) {
        TypeAlias a = new TypeAlias();
        that.setDeclarationModel(a);
        visitDeclaration(that, a);
        Scope o = enterScope(a);
        super.visit(that);
        exitScope(o);
    }
   
    @Override
    public void visit(Tree.TypeParameterDeclaration that) {
        Tree.TypeSpecifier ts = that.getTypeSpecifier();
        Tree.TypeVariance tv = that.getTypeVariance();
        TypeParameter p = new TypeParameter();
        defaultExtendedToAnything(p);
        p.setDeclaration(declaration);
        p.setDefaulted(ts!=null);
        if (tv!=null) {
            String v = tv.getText();
            p.setCovariant("out".equals(v));
            p.setContravariant("in".equals(v));
        }
        that.setDeclarationModel(p);
        visitDeclaration(that, p);
        super.visit(that);
        if (ts!=null) {
            Tree.StaticType type = ts.getType();
            if (type!=null) {
                p.setDefaultTypeArgument(type.getTypeModel());
            }
        }
    }
   
    @Override
    public void visit(Tree.AnyMethod that) {
        Method m = new Method();
        that.setDeclarationModel(m);
        visitDeclaration(that, m);
        Scope o = enterScope(m);
        super.visit(that);
        exitScope(o);
        setParameterLists(m, that.getParameterLists(), that);
        Tree.Type type = that.getType();
        m.setDeclaredVoid(type instanceof Tree.VoidModifier);
        if (type instanceof Tree.ValueModifier) {
            type.addError("functions may not be declared using the keyword value");
        }
        if (type instanceof Tree.DynamicModifier) {
            m.setDynamicallyTyped(true);
        }
    }

    private static void setParameterLists(Method m, List<Tree.ParameterList> paramLists,
            Node that) {
        if (m!=null) {
            for (Tree.ParameterList pl: paramLists) {
                m.addParameterList(pl.getModel());
            }
        }
        if (paramLists.isEmpty()) {
            that.addError("missing parameter list in function declaration", 1000);
        }
        else {
            paramLists.get(0).getModel().setFirst(true);
        }
    }
   
    @Override
    public void visit(Tree.AnyAttribute that) {
        super.visit(that);
        Tree.Type type = that.getType();
        if (type instanceof Tree.FunctionModifier) {
            type.addError("values may not be declared using the keyword function");
        }
        if (type instanceof Tree.DynamicModifier) {
            that.getDeclarationModel().setDynamicallyTyped(true);
        }
    }

    @Override
    public void visit(Tree.MethodArgument that) {
        Method m = new Method();
        that.setDeclarationModel(m);
        visitArgument(that, m);
        Scope o = enterScope(m);
        super.visit(that);
        exitScope(o);
        setParameterLists(m, that.getParameterLists(), that);
        m.setDeclaredVoid(that.getType() instanceof Tree.VoidModifier);
    }
   
    private int fid=0;

    @Override
    public void visit(Tree.FunctionArgument that) {
        Method m = new Method();
        m.setName("anonymous#"+fid++);
        m.setAnonymous(true);
        that.setDeclarationModel(m);
        visitArgument(that, m);
        Scope o = enterScope(m);
        Declaration d = beginDeclaration(that.getDeclarationModel());
        super.visit(that);
        endDeclaration(d);
        exitScope(o);
        setParameterLists(m, that.getParameterLists(), that);
        m.setDeclaredVoid(that.getType() instanceof Tree.VoidModifier);
    }
   
    @Override
    public void visit(Tree.ObjectDefinition that) {
        /*if (that.getClassBody()==null) {
            that.addError("missing object body");
        }*/
        Class c = new Class();
        defaultExtendedToBasic(c);
        c.setAnonymous(true);
        that.setAnonymousClass(c);
        visitDeclaration(that, c);
        Value v = new Value();
        that.setDeclarationModel(v);
        visitDeclaration(that, v);
        that.getType().setTypeModel(c.getType());
        v.setType(c.getType());
        Scope o = enterScope(c);
        super.visit(that);
        exitScope(o);
        if (c.isInterfaceMember()) {
            that.addError("object declaration may not occur directly in interface body");
        }
    }

    @Override
    public void visit(Tree.ObjectArgument that) {
        /*if (that.getClassBody()==null) {
            that.addError("missing named argument body");
        }*/
        Class c = new Class();
        defaultExtendedToBasic(c);
        c.setAnonymous(true);
        that.setAnonymousClass(c);
        visitArgument(that, c);
        Value v = new Value();
        that.setDeclarationModel(v);
        visitArgument(that, v);
        that.getType().setTypeModel(c.getType());
        v.setType(c.getType());
        Scope o = enterScope(c);
        super.visit(that);
        exitScope(o);
    }
   
    @Override
    public void visit(Tree.AttributeDeclaration that) {
        Value v = new Value();
        that.setDeclarationModel(v);
        v.setTransient(that.getSpecifierOrInitializerExpression()
                instanceof Tree.LazySpecifierExpression);
        visitDeclaration(that, v);
        super.visit(that);
        if (v.isInterfaceMember() && !v.isFormal() && !v.isNative()) {
            if (that.getSpecifierOrInitializerExpression()==null) {
                that.addError("interface attribute must be annotated formal", 1400);
            }
            /*else {
                that.addError("interfaces may not have simple attributes");
            }*/
        }
        if (v.isLate()) {
            if (v.isFormal()) {
                that.addError("formal attribute may not be annotated late");
            }
            else if (!v.isClassOrInterfaceMember() && !v.isToplevel()) {
                that.addError("block-local value may not be annotated late");
            }
        }
        Tree.SpecifierOrInitializerExpression sie = that.getSpecifierOrInitializerExpression();
        if ( v.isFormal() && sie!=null ) {
            that.addError("formal attributes may not have a value", 1307);
        }
        Tree.Type type = that.getType();
        if (type instanceof Tree.ValueModifier) {
            if (v.isToplevel()) {
                if (sie==null) {
                    type.addError("toplevel values must explicitly specify a type");
                }
                else {
                    type.addError("toplevel value must explicitly specify a type", 200);
                }
            }
            else if (v.isShared()) {
                type.addError("shared value must explicitly specify a type", 200);
            }
        }
    }

    @Override
    public void visit(Tree.MethodDeclaration that) {
        super.visit(that);
        Tree.SpecifierExpression sie = that.getSpecifierExpression();
        if ( that.getDeclarationModel().isFormal() && sie!=null ) {
            that.addError("formal methods may not have a specification", 1307);
        }
        Method m = that.getDeclarationModel();
        Tree.Type type = that.getType();
        if (type instanceof Tree.FunctionModifier) {
            if (m.isToplevel()) {
                if (sie==null) {
                    type.addError("toplevel function must explicitly specify a return type");
                }
                else {
                    type.addError("toplevel function must explicitly specify a return type", 200);
                }
            }
            else if (m.isShared()) {
                type.addError("shared function must explicitly specify a return type", 200);
            }
        }
    }
           
    @Override
    public void visit(Tree.MethodDefinition that) {
        super.visit(that);
        Method m = that.getDeclarationModel();
        if (that.getType() instanceof Tree.FunctionModifier) {
            if (m.isToplevel()) {
                that.getType().addError("toplevel function must explicitly specify a return type", 200);
            }
            else if (m.isShared() && !dynamic) {
                that.getType().addError("shared function must explicitly specify a return type", 200);
            }
        }
    }
           
    @Override
    public void visit(Tree.AttributeGetterDefinition that) {
        Value g = new Value();
        g.setTransient(true);
        that.setDeclarationModel(g);
        visitDeclaration(that, g);
        Scope o = enterScope(g);
        super.visit(that);
        exitScope(o);
        if (that.getType() instanceof Tree.ValueModifier) {
            if (g.isToplevel()) {
                that.getType().addError("toplevel getter must explicitly specify a type", 200);
            }
            else if (g.isShared() && !dynamic) {
                that.getType().addError("shared getter must explicitly specify a type", 200);
            }
        }
    }
   
    @Override
    public void visit(Tree.AttributeArgument that) {
        Value g = new Value();
        g.setTransient(true);
        that.setDeclarationModel(g);
        visitArgument(that, g);
        Scope o = enterScope(g);
        super.visit(that);
        exitScope(o);
    }
   
    @Override
    public void visit(Tree.AttributeSetterDefinition that) {
        Setter s = new Setter();
        that.setDeclarationModel(s);
        visitDeclaration(that, s);
        Scope o = enterScope(s);
        Parameter p = new Parameter();
        p.setHidden(true);
        Value v = new Value();
        v.setInitializerParameter(p);
        p.setModel(v);
        v.setName(s.getName());
        p.setName(s.getName());
        p.setDeclaration(s);
        visitElement(that, v);
        unit.addDeclaration(v);
        Scope sc = getContainer(that);
        sc.addMember(v);
       
        s.setParameter(p);
        super.visit(that);
        exitScope(o);
       
        if (that.getSpecifierExpression()==null &&
                that.getBlock()==null) {
            that.addError("setter declaration must have a body or => specifier");
        }
    }

    @Override
    public void visit(Tree.MissingDeclaration that) {
        Value value = new Value();
        that.setDeclarationModel(value);
        visitDeclaration(that, value);
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.InitializerParameter that) {
        Parameter p = new Parameter();
        p.setDeclaration(declaration);
        p.setDefaulted(that.getSpecifierExpression()!=null);
        p.setHidden(true);
        p.setName(that.getIdentifier().getText());
        that.setParameterModel(p);
//        visitDeclaration(that, p);
        super.visit(that);
        parameterList.getParameters().add(p);
    }

    @Override
    public void visit(Tree.Parameter that) {
        super.visit(that);
        Tree.SpecifierOrInitializerExpression sie = null;
        if (that instanceof Tree.ParameterDeclaration) {
            Tree.TypedDeclaration td = ((Tree.ParameterDeclaration) that).getTypedDeclaration();
            if (td instanceof Tree.AttributeDeclaration) {
                sie = ((Tree.AttributeDeclaration) td).getSpecifierOrInitializerExpression();
            }
            else if (td instanceof Tree.MethodDeclaration) {
                sie = ((Tree.MethodDeclaration) td).getSpecifierExpression();
            }
        }
        else if (that instanceof Tree.InitializerParameter) {
            sie = ((Tree.InitializerParameter) that).getSpecifierExpression();
        }
        if (sie!=null) {
            new Visitor() {
                public void visit(Tree.AssignmentOp that) {
                    that.addError("assignment may not occur in default argument expression");
                }
                @Override
                public void visit(Tree.PostfixOperatorExpression that) {
                    that.addError("postfix increment or decrement may not occur in default argument expression");
                }
                @Override
                public void visit(Tree.PrefixOperatorExpression that) {
                    that.addError("prefix increment or decrement may not occur in default argument expression");
                }
            }.visit(sie);
        }
    }
   
    private static Tree.SpecifierOrInitializerExpression getSpecifier(
            Tree.ValueParameterDeclaration that) {
        return ((Tree.AttributeDeclaration) that.getTypedDeclaration())
                .getSpecifierOrInitializerExpression();
    }

    private static Tree.SpecifierExpression getSpecifier(
            Tree.FunctionalParameterDeclaration that) {
        return ((Tree.MethodDeclaration) that.getTypedDeclaration())
                .getSpecifierExpression();
    }
   
    @Override
    public void visit(Tree.ValueParameterDeclaration that) {
        Parameter p = new Parameter();
        p.setDeclaration(declaration);
        p.setDefaulted(getSpecifier(that)!=null);
        Tree.Type type = that.getTypedDeclaration().getType();
        p.setSequenced(type instanceof Tree.SequencedType);
        that.setParameterModel(p);
        super.visit(that);
        Value v = (Value) that.getTypedDeclaration().getDeclarationModel();
        p.setName(v.getName());
        p.setModel(v);
        v.setInitializerParameter(p);
        parameterList.getParameters().add(p);
        if (p.isSequenced() && p.isDefaulted()) {
            getSpecifier(that).addError("variadic parameter may not specify default argument");
        }
        if (p.isSequenced() && ((Tree.SequencedType) type).getAtLeastOne()) {
//            that.getType().addWarning("nonempty variadic parameters are not yet supported");
            p.setAtLeastOne(true);
        }
        if (v.isFormal()) {
            that.addError("parameters may not be annotated formal", 1312);
        }
//        if (v.isVariable()) {
//            that.addError("parameter may not be annotated variable");
//        }
    }

    @Override
    public void visit(Tree.FunctionalParameterDeclaration that) {
        Parameter p = new Parameter();
        p.setDeclaration(declaration);
        p.setDefaulted(getSpecifier(that)!=null);
        Tree.Type type = that.getTypedDeclaration().getType();
        p.setDeclaredAnything(type instanceof Tree.VoidModifier);
        that.setParameterModel(p);
        super.visit(that);
        Method m = (Method) that.getTypedDeclaration().getDeclarationModel();
        p.setModel(m);
        p.setName(m.getName());
        m.setInitializerParameter(p);
        parameterList.getParameters().add(p);
        if (type instanceof Tree.SequencedType) {
            type.addError("functional parameter type may not be variadic");
        }
        if (m.isFormal()) {
            that.addError("parameters may not be annotated formal", 1312);
        }
    }

    @Override
    public void visit(Tree.ParameterList that) {
        ParameterList pl = parameterList;
        parameterList = new ParameterList();
        that.setModel(parameterList);
        super.visit(that);
        parameterList = pl;       
    }
   
    private int id=0;
   
    @Override
    public void visit(Tree.ControlClause that) {
        ControlBlock cb = new ControlBlock();
        cb.setId(id++);
        that.setControlBlock(cb);
        visitElement(that, cb);
        Scope o = enterScope(cb);
        super.visit(that);
        exitScope(o);
    }
   
    @Override
    public void visit(Tree.Condition that) {
        ConditionScope cb = new ConditionScope();
        cb.setId(id++);
        that.setScope(cb);
        visitElement(that, cb);
        enterScope(cb);
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.ExistsOrNonemptyCondition that) {
        super.visit(that);
        String op = that instanceof Tree.ExistsCondition ? "exists" : "nonempty";
        if (that.getBrokenExpression()!=null) {
            that.getBrokenExpression()
                .addError("incorrect syntax: " + op +
                        " conditions do not apply to arbitrary expressions, try using postfix " +
                        op + " operator", 3100);
        }
        else if (that.getVariable()==null) {
            that.addError("missing variable or immutable value reference: " + op +
                    " condition requires an operand");
        }
    }
   
    @Override
    public void visit(Tree.Body that) {
        int oid=id;
        id=0;
        super.visit(that);
        id=oid;
    }
   
    @Override
    public void visit(Tree.NamedArgumentList that) {
        NamedArgumentList nal = new NamedArgumentList();
        nal.setId(id++);
        for (Tree.NamedArgument na: that.getNamedArguments()) {
            if (na.getIdentifier()!=null) {
                nal.getArgumentNames().add(na.getIdentifier().getText());
            }
        }
        that.setNamedArgumentList(nal);
        visitElement(that, nal);
        Scope o = enterScope(nal);
        super.visit(that);
        exitScope(o);
    }
   
    @Override
    public void visit(Tree.Variable that) {
        if (that.getSpecifierExpression()!=null) {
            Scope s = scope;
            if (scope instanceof ControlBlock) {
                scope = scope.getContainer();
            }
            that.getSpecifierExpression().visit(this);
            scope = s;
        }
       
        Value v = new Value();
        that.setDeclarationModel(v);
        visitDeclaration(that, v, !(that.getType() instanceof Tree.SyntheticVariable));
        setVisibleScope(v);
       
        if (that.getType()!=null) {
            that.getType().visit(this);
        }
        if (that.getIdentifier()!=null) {
            that.getIdentifier().visit(this);
        }
       
        //TODO: scope should be the variable, not the
        //      containing control structure:
        if (that.getAnnotationList()!=null) {
            that.getAnnotationList().visit(this);
        }
        for (Tree.ParameterList pl: that.getParameterLists()) {
            pl.visit(this);
        }
       
        //TODO: parameters of callable variables are allowed
        //      in for loops, according to the language spec
        /*Declaration od = beginDeclaration(v);
        Scope os = enterScope(v);
        if (that.getAnnotationList()!=null) {
            that.getAnnotationList().visit(this);
        }
        for (Tree.ParameterList pl: that.getParameterLists()) {
            pl.visit(this);
        }
        exitScope(os);
        endDeclaration(od);
        */
       
        if (that.getParameterLists().isEmpty()) {
            if (that.getType() instanceof Tree.FunctionModifier) {
                that.getType().addError("variables with no parameters may not be declared using the keyword function");
            }
            if (that.getType() instanceof Tree.VoidModifier) {
                that.getType().addError("variables with no parameters may not be declared using the keyword void");
            }
        }
        else {
            Tree.ParameterList pl = that.getParameterLists().get(0);
            pl.addUnsupportedError("variables with parameter lists are not yet supported");
            if (that.getType() instanceof Tree.ValueModifier) {
                that.getType().addError("variables with parameters may not be declared using the keyword value");
            }
        }
               
        that.setScope(scope);
        that.setUnit(unit);
    }
   
    private static List<TypeParameter> getTypeParameters(Tree.TypeParameterList tpl) {
        List<TypeParameter> typeParameters = Collections.emptyList();
        if (tpl!=null) {
            boolean foundDefaulted=false;
            List<TypeParameterDeclaration> tpds = tpl.getTypeParameterDeclarations();
            typeParameters = new ArrayList<TypeParameter>(tpds.size());
            for (Tree.TypeParameterDeclaration tp: tpds) {
                typeParameters.add(tp.getDeclarationModel());
                if (tp.getTypeSpecifier()==null) {
                    if (foundDefaulted) {
                        tp.addError("required type parameter follows defaulted type parameter");
                    }
                }
                else {
                    foundDefaulted=true;
                }
            }
        }
        return typeParameters;
    }
   
    @Override
    public void visit(Tree.ModuleDescriptor that) {
        if (!unit.getFilename().equals("module.ceylon")) {
            that.addError("module descriptor must occur in a compilation unit named module.ceylon");
        }
        super.visit(that);
    }
   
    @Override
    public void visit(Tree.PackageDescriptor that) {
        if (!unit.getFilename().equals("package.ceylon")) {
            that.addError("package descriptor must occur in a compilation unit named package.ceylon");
        }
        super.visit(that);
    }
   
    @Override public void visit(Tree.Declaration that) {
        if (unit.getFilename().equals("module.ceylon") ||
            unit.getFilename().equals("package.ceylon")) {
            that.addError("declaration may not occur in a module or package descriptor file");
        }
        Declaration model = that.getDeclarationModel();
        Declaration d = beginDeclaration(model);
        super.visit(that);
        endDeclaration(d);
        if (model.isClassOrInterfaceMember() &&
                ((ClassOrInterface) model.getContainer()).isFinal()) {
            if (model.isDefault()) {
                that.addError("member of final class may not be annotated default");
            }
        }
        if (model.isToplevel()) {
            if (model.getName()!=null &&
                model.getName().endsWith("_")) {
                that.addUnsupportedError("toplevel declaration name ending in _ not currently supported");
            }
            if (pkg.getNameAsString().endsWith("_")) {
                that.addUnsupportedError("toplevel declaration belonging to package with name ending in _ not currently supported");
            }
        }
    }

    private void handleDeclarationAnnotations(Tree.Declaration that,
            Declaration model) {
        Tree.AnnotationList al = that.getAnnotationList();
        if (hasAnnotation(al, "shared", unit)) {
            if (that instanceof Tree.AttributeSetterDefinition) {
                that.addError("setter may not be annotated shared", 1201);
            }
            /*else if (that instanceof Tree.TypedDeclaration && !(that instanceof Tree.ObjectDefinition)) {
                Tree.Type t =  ((Tree.TypedDeclaration) that).getType();
                if (t instanceof Tree.ValueModifier || t instanceof Tree.FunctionModifier) {
                    t.addError("shared declarations must explicitly specify a type", 200);
                }
                else {
                    model.setShared(true);
                }
            }*/
            else {
                model.setShared(true);
            }
        }
        if (hasAnnotation(al, "default", unit)) {
            if (that instanceof Tree.ObjectDefinition) {
                that.addError("object declaration may not be annotated default", 1313);
            }
            /*else if (that instanceof Tree.Parameter) {
                that.addError("parameters may not be annotated default", 1313);
            }*/
            else {
                model.setDefault(true);
            }
        }
        if (hasAnnotation(al, "formal", unit)) {
            if (that instanceof Tree.ObjectDefinition) {
                that.addError("object declaration may not be annotated formal", 1312);
            }
            else {
                model.setFormal(true);
            }
        }
        if (hasAnnotation(al, "native", unit)) {
            model.setNative(true);
        }
        if (model.isFormal() && model.isDefault()) {
            that.addError("declaration may not be annotated both formal and default");
        }
        if (hasAnnotation(al, "actual", unit)) {
            model.setActual(true);
        }
        if (hasAnnotation(al, "abstract", unit)) {
            if (model instanceof Class) {
                ((Class) model).setAbstract(true);
            }
            else {
                that.addError("declaration is not a class, and may not be annotated abstract", 1600);
            }
        }
        if (hasAnnotation(al, "final", unit)) {
            if (model instanceof Class) {
                ((Class) model).setFinal(true);
            }
            else {
                that.addError("declaration is not a class, and may not be annotated final", 1700);
            }
        }
        if (hasAnnotation(al, "sealed", unit)) {
            if (model instanceof ClassOrInterface) {
                ((ClassOrInterface) model).setSealed(true);
            }
            else {
                that.addError("declaration is not a class or interface, and may not be annotated sealed");
            }
        }
        if (hasAnnotation(al, "variable", unit)) {
            if (model instanceof Value) {
                ((Value) model).setVariable(true);
            }
            else {
                that.addError("declaration is not a value, and may not be annotated variable", 1500);
            }
        }
        if (hasAnnotation(al, "late", unit)) {
            if (model instanceof Value) {
                if (that instanceof Tree.AttributeDeclaration &&
                        ((Tree.AttributeDeclaration) that).getSpecifierOrInitializerExpression()==null) {
                    ((Value) model).setLate(true);
                }
                else {
                    that.addError("value is not an uninitialized reference, and may not be annotated late");
                }
            }
            else {
                that.addError("declaration is not a value, and may not be annotated late");
            }
        }
        if (model instanceof Value) {
            Value value = (Value) model;
            if (value.isVariable() && value.isTransient()) {
                that.addError("getter may not be annotated variable: '" + model.getName() + "'");
            }
        }
        if (hasAnnotation(al, "deprecated", unit)) {
            model.setDeprecated(true);
        }
        if (hasAnnotation(al, "annotation", unit)) {
            if (!(model instanceof Method) && !(model instanceof Class)) {
                that.addError("declaration is not a function or class, and may not be annotated annotation");
            }
            else if (!model.isToplevel()) {
                that.addError("declaration is not toplevel, and may not be annotated annotation");
            }
            else {
                model.setAnnotation(true);
            }
        }
       
        buildAnnotations(al, model.getAnnotations());       
    }

    public static void setVisibleScope(Declaration model) {
        Scope s=model.getContainer();
        while (s!=null) {
            if (s instanceof Declaration) {
                if (model.isShared()) {
                    if (!((Declaration) s).isShared()) {
                        model.setVisibleScope(s.getContainer());
                        break;
                    }
                }
                else {
                    model.setVisibleScope(s);
                    break;
                }
            }
            else if (s instanceof Package) {
                //TODO: unshared packages!
                /*if (!((Package) s).isShared()) {
                    model.setVisibleScope(s);
                }*/
                if (!model.isShared()) {
                    model.setVisibleScope(s);
                }
                //null visible scope means visible everywhere
                break;
            }
            else {
                model.setVisibleScope(s);
                break;
            }   
            s = s.getContainer();
        }
    }

    private static void checkFormalMember(Tree.Declaration that, Declaration d) {
       
        Scope container = d.getContainer();
        if (d.isFormal()) {
            if (container instanceof ClassOrInterface) {
                //handled in RefinementVisitor
//                ClassOrInterface ci = (ClassOrInterface) d.getContainer();
//                if (!ci.isAbstract() && !ci.isFormal()) {
//                    that.addError("formal member belongs to a concrete class", 900);
//                }
                if (d instanceof Class) {
                    if (((Class) d).isSealed() &&
                            !((ClassOrInterface) container).isSealed()) {
                        that.addError("sealed formal member class does not belong to a sealed type");
                    }
                }
            }
            else {
                that.addError("formal member does not belong to an interface or abstract class", 1100);
            }
            if (!(that instanceof Tree.AttributeDeclaration) &&
                !(that instanceof Tree.MethodDeclaration) &&
                !(that instanceof Tree.AnyClass)) {
                that.addError("formal member may not have a body", 1101);
            }
        }
       
        if (d.isNative()) {
            if (container instanceof Declaration) {
                Declaration ci = (Declaration) container;
                if (!ci.isNative()) {
                    that.addError("native member belongs to a non-native declaration: '" +
                            d.getName() + "' of '" + ci.getName());
                }
            }
        }
       
        /*if ( !d.isFormal() &&
                d.getContainer() instanceof Interface &&
                !(that instanceof Tree.TypeParameterDeclaration) &&
                !(that instanceof Tree.ClassDeclaration) &&
                !(that instanceof Tree.InterfaceDeclaration)) {
            that.addWarning("concrete members of interfaces not yet supported");
        }*/
       
    }
       
    @Override public void visit(Tree.TypedArgument that) {
        Declaration d = beginDeclaration(that.getDeclarationModel());
        super.visit(that);
        endDeclaration(d);
        //that.addWarning("declaration-style named arguments not yet supported");
    }

    @Override
    public void visit(Tree.TypeConstraint that) {
        String name = name(that.getIdentifier());
        TypeParameter p = (TypeParameter) scope.getDirectMember(name, null, false);
        that.setDeclarationModel(p);
        if (p==null) {
            that.addError("no matching type parameter for constraint: '" +
                    name + "'");
            p = new TypeParameter();
            p.setDeclaration(declaration);
            that.setDeclarationModel(p);
            visitDeclaration(that, p);
        }
        else {
          if (p.isConstrained()) {
            that.addError("duplicate constraint list for type parameter: '" +
                name + "'");
          }
          p.setConstrained(true);
        }
       
        Scope o = enterScope(p);
        super.visit(that);
        exitScope(o);
       
        if ( that.getAbstractedType()!=null ) {
            that.addUnsupportedError("lower bound type constraints are not yet supported");
        }
        /*if ( that.getCaseTypes()!=null ) {
            that.addWarning("enumerated type constraints are not yet supported");
        }*/
        if ( that.getParameterList()!=null ) {
            that.addUnsupportedError("parameter bounds are not yet supported");
            that.getParameterList().getModel().setFirst(true);
            p.addParameterList(that.getParameterList().getModel());
        }
    }
   
    @Override
    public void visit(Tree.ParameterizedExpression that) {
        super.visit(that);
        setParameterLists(null, that.getParameterLists(), that);
        if (!that.getLeftTerm()) {
            that.addError("parameterized expression not the target of a specification statement");
        }
    }
   
    @Override
    public void visit(Tree.SpecifierStatement that) {
        Tree.Term lhs = that.getBaseMemberExpression();
        if (lhs instanceof Tree.ParameterizedExpression) {
            ((Tree.ParameterizedExpression) lhs).setLeftTerm(true);
        }
        Specification s = new Specification();
        s.setId(id++);
        visitElement(that, s);
        Scope o = enterScope(s);
        super.visit(that);
        exitScope(o);
    }
   
    /*@Override
    public void visit(Tree.SpecifiedArgument that) {
        Specification s = new Specification();
        visitElement(that, s);
        Scope o = enterScope(s);
        super.visit(that);
        exitScope(o);
    }*/
   
    @Override
    public void visit(Tree.SatisfiesCondition that) {
        super.visit(that);
        that.addUnsupportedError("satisfies conditions are not yet supported");
    }
   
    /*@Override
    public void visit(Tree.Comprehension that) {
        super.visit(that);
        that.addWarning("comprehensions are not yet supported");
    }*/
   
    @Override
    public void visit(Tree.Assertion that) {
        Declaration d = beginDeclaration(null);
        super.visit(that);
        endDeclaration(d);
    }   
   
    /*@Override
    public void visit(Tree.AnnotationList that) {
        Scope s = scope;
        if (declaration instanceof Scope) {
            scope = scope.getContainer();
        }
        super.visit(that);
        scope = s;
    }*/
   
    @Override
    public void visit(Tree.Annotation that) {
        super.visit(that);
        that.getPrimary().setScope(pkg);
    }
   
    @Override
    public void visit(Tree.TypeArgumentList that) {
        super.visit(that);
        if (that.getTypes().isEmpty()) {
            that.addError("type argument list must have at least one type");
        }
    }
   
    @Override
    public void visit(Tree.PositionalArgumentList that) {
        super.visit(that);
        checkPositionalArguments(that.getPositionalArguments());
    }
   
    @Override
    public void visit(Tree.SequencedArgument that) {
        super.visit(that);
        checkPositionalArguments(that.getPositionalArguments());
    }
   
    private void checkPositionalArguments(List<Tree.PositionalArgument> args) {
        for (int i=0; i<args.size()-1; i++) {
            Tree.PositionalArgument a = args.get(i);
            if (a instanceof Tree.SpreadArgument) {
                a.addError("spread argument must be the last argument in the argument list");
            }
            if (a instanceof Tree.Comprehension) {
                a.addError("comprehension must be the last argument in the argument list");
            }
        }
    }   
   
    @Override
    public void visit(Tree.TryCatchStatement that) {
        super.visit(that);
        if (that.getTryClause().getBlock()!=null &&
                that.getCatchClauses().isEmpty() &&
                that.getFinallyClause()==null &&
                that.getTryClause().getResourceList()==null) {
            that.addError("try must have a catch, finally, or resource expression");
        }
    }
   
    @Override
    public void visit(Tree.Import that) {
        super.visit(that);
        Tree.ImportPath path = that.getImportPath();
        if (path!=null &&
                formatPath(path.getIdentifiers()).equals(Module.LANGUAGE_MODULE_NAME)) {
            Tree.ImportMemberOrTypeList imtl = that.getImportMemberOrTypeList();
            if (imtl!=null) {
                for (Tree.ImportMemberOrType imt: imtl.getImportMemberOrTypes()) {
                    if (imt.getAlias()!=null && imt.getIdentifier()!=null) {
                        String name = name(imt.getIdentifier());
                        String alias = name(imt.getAlias().getIdentifier());
                        Map<String, String> mods = unit.getModifiers();
                        if (mods.containsKey(name)) {
//                            String curr = mods.get(alias);
//                            if (curr!=null && curr.equals(alias)) {
//                                mods.remove(alias);
//                            }
                            mods.put(name, alias);
                        }
                    }
                }
            }
        }
    }
   
    private boolean declarationReference=false;
   
    @Override
    public void visit(Tree.MetaLiteral that) {
        declarationReference = that instanceof Tree.ClassLiteral ||
                that instanceof Tree.InterfaceLiteral ||
                that instanceof Tree.AliasLiteral ||
                that instanceof Tree.TypeParameterLiteral ||
                that instanceof Tree.ValueLiteral ||
                that instanceof Tree.FunctionLiteral;
        super.visit(that);
        declarationReference = false;
    }
   
    @Override
    public void visit(Tree.StaticType that) {
        that.setMetamodel(declarationReference);
        super.visit(that);
    }
   
    private boolean inExtends;
   
    @Override
    public void visit(final Tree.BaseType that) {
        super.visit(that);
        final Scope scope = that.getScope();
        final String name = name(that.getIdentifier());
        if (inExtends) {
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    return getTypeDeclaration(scope,
                            name, null, false, unit);
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    Tree.TypeArgumentList tal = that.getTypeArgumentList();
                    return getTypeArgumentMap(getDeclaration(), null,
                            Util.getTypeArguments(tal,
                                    getDeclaration().getTypeParameters(), null));
                }
            };
            that.setTypeModel(t);
        }
    }
   
    @Override
    public void visit(final Tree.QualifiedType that) {
        super.visit(that);
        final String name = name(that.getIdentifier());
        final ProducedType outerType = that.getOuterType().getTypeModel();
        if (inExtends) {
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    if (outerType==null) {
                        return null;
                    }
                    else {
                        return Util.getTypeMember(outerType.getDeclaration(),
                                name, null, false, unit);
                    }
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    Tree.TypeArgumentList tal = that.getTypeArgumentList();
                    if (outerType==null) {
                        return emptyMap();
                    }
                    else {
                        return getTypeArgumentMap(getDeclaration(), outerType,
                                Util.getTypeArguments(tal,
                                        getDeclaration().getTypeParameters(),
                                        outerType));
                    }
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.IterableType that) {
        super.visit(that);
        if (inExtends) {
            final ProducedType elementType;
            final boolean atLeastOne;
            Tree.Type elem = that.getElementType();
            if (elem==null) {
              elementType = unit.getNothingDeclaration().getType();
              atLeastOne = false;
            }
            else if (elem instanceof Tree.SequencedType) {
              Tree.SequencedType set = (Tree.SequencedType) elem;
              elementType = set.getType().getTypeModel();
              atLeastOne = set.getAtLeastOne();
            }
            else {
              elementType = null;
              atLeastOne = false;
            }
            ProducedType t = new LazyProducedType(unit) {
                ProducedType iterableType() {
                    if (elementType!=null) {
                        return atLeastOne ?
                                unit.getNonemptyIterableType(elementType) :
                                unit.getIterableType(elementType);
                    }
                    else {
                        return unit.getIterableType(new UnknownType(unit).getType());
                    }
                }
                @Override
                public TypeDeclaration initDeclaration() {
                    return iterableType().getDeclaration();
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    return iterableType().getTypeArguments();
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.TupleType that) {
        super.visit(that);
        if (inExtends) {
            ProducedType t = new LazyProducedType(unit) {
                private ProducedType tupleType(final Tree.TupleType that) {
                    //TODO: this holds a hard reference to the Tree.Type
                    return getTupleType(that.getElementTypes(), unit);
                }
                @Override
                public TypeDeclaration initDeclaration() {
                    return tupleType(that).getDeclaration();
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    return tupleType(that).getTypeArguments();
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.OptionalType that) {
        super.visit(that);
        final ProducedType definiteType = that.getDefiniteType().getTypeModel();
        if (inExtends) {
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    List<ProducedType> types =
                            new ArrayList<ProducedType>(2);
                    types.add(unit.getType(unit.getNullDeclaration()));
                    if (definiteType!=null) types.add(definiteType);
                    UnionType ut = new UnionType(unit);
                    ut.setCaseTypes(types);
                    return ut;
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    return emptyMap();
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.UnionType that) {
        super.visit(that);
        final List<ProducedType> types =
                new ArrayList<ProducedType>(that.getStaticTypes().size());
        for (Tree.StaticType st: that.getStaticTypes()) {
            ProducedType t = st.getTypeModel();
            if (t!=null) {
                types.add(t);
            }
        }
        if (inExtends) {
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    UnionType ut = new UnionType(unit);
                    ut.setCaseTypes(types);
                    return ut;
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    return emptyMap();
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.IntersectionType that) {
        super.visit(that);
        if (inExtends) {
            final List<ProducedType> types =
                    new ArrayList<ProducedType>(that.getStaticTypes().size());
            for (Tree.StaticType st: that.getStaticTypes()) {
                ProducedType t = st.getTypeModel();
                if (t!=null) types.add(t);
            }
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    IntersectionType it = new IntersectionType(unit);
                    it.setSatisfiedTypes(types);
                    return it;
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    return emptyMap();
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.SequenceType that) {
        super.visit(that);
        if (inExtends) {
            final ProducedType elementType =
                    that.getElementType().getTypeModel();
            final NaturalLiteral length = that.getLength();
            ProducedType t;
            if (length==null) {
                t = new LazyProducedType(unit) {
                    @Override
                    public TypeDeclaration initDeclaration() {
                        return unit.getSequentialDeclaration();
                    }
                    @Override
                    public Map<TypeParameter, ProducedType> initTypeArguments() {
                        List<TypeParameter> stps =
                                unit.getSequentialDeclaration().getTypeParameters();
                        return singletonMap(stps.get(0), elementType);
                    }
                };
            }
            else {
                final int len;
                try {
                    len = Integer.parseInt(length.getText());
                }
                catch (NumberFormatException nfe) {
                    return;
                }
                if (len<1 || len>100) {
                    return;
                }
                else {
                    t = new StaticLengthSequenceType(elementType, len);
                }
            }
            that.setTypeModel(t);
        }
    }
   
    private final class StaticLengthSequenceType extends LazyProducedType {
        private final ProducedType elementType;
        private final int len;

        private StaticLengthSequenceType(ProducedType elementType, int len) {
            super(unit);
            this.elementType = elementType;
            this.len = len;
        }

        @Override
        public TypeDeclaration initDeclaration() {
            return unit.getTupleDeclaration();
        }

        @Override
        public Map<TypeParameter,ProducedType> initTypeArguments() {
            List<TypeParameter> stps =
                    unit.getTupleDeclaration().getTypeParameters();
            Map<TypeParameter,ProducedType> args =
                    new HashMap<TypeParameter,ProducedType>(3);
            args.put(stps.get(0), elementType);
            args.put(stps.get(1), elementType);
            args.put(stps.get(3),
                    len==1 ? unit.getEmptyDeclaration().getType() :
                             new StaticLengthSequenceType(elementType, len-1));
            return args;
        }
    }

    public void visit(final Tree.SequencedType that) {
        super.visit(that);
        if (inExtends) {
            final ProducedType type = that.getType().getTypeModel();
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    return that.getAtLeastOne() ?
                            unit.getSequenceDeclaration() :
                            unit.getSequentialDeclaration();
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    List<TypeParameter> stps =
                            (that.getAtLeastOne() ?
                                    unit.getSequenceDeclaration() :
                                    unit.getSequentialDeclaration())
                            .getTypeParameters();
                    return singletonMap(stps.get(0), type);
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.EntryType that) {
        super.visit(that);
        if (inExtends) {
            final ProducedType keyType = that.getKeyType().getTypeModel();
            final ProducedType valueType = that.getValueType().getTypeModel();
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    return unit.getEntryDeclaration();
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    HashMap<TypeParameter, ProducedType> map =
                            new HashMap<TypeParameter, ProducedType>();
                    List<TypeParameter> itps =
                            unit.getEntryDeclaration().getTypeParameters();
                    map.put(itps.get(0), keyType);
                    map.put(itps.get(1), valueType);
                    return map;
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.FunctionType that) {
        super.visit(that);
        if (inExtends) {
            final ProducedType returnType =
                    that.getReturnType().getTypeModel();
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    return unit.getCallableDeclaration();
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    HashMap<TypeParameter, ProducedType> map =
                            new HashMap<TypeParameter, ProducedType>();
                    List<TypeParameter> ctps =
                            unit.getCallableDeclaration().getTypeParameters();
                    map.put(ctps.get(0), returnType);
                    map.put(ctps.get(1),
                            //TODO: holds on to reference to Tree.Type
                            getTupleType(that.getArgumentTypes(), unit));
                    return map;
                }
            };
            that.setTypeModel(t);
        }
    }
   
    public void visit(final Tree.SuperType that) {
        super.visit(that);
        if (inExtends) {
            final Scope scope = that.getScope();
            ProducedType t = new LazyProducedType(unit) {
                @Override
                public TypeDeclaration initDeclaration() {
                    ClassOrInterface ci =
                            getContainingClassOrInterface(scope);
                    if (ci==null) {
                        return null;
                    }
                    else {
                        if (ci.isClassOrInterfaceMember()) {
                            ClassOrInterface oci =
                                    (ClassOrInterface) ci.getContainer();
                            return intersectionOfSupertypes(oci).getDeclaration();
                        }
                        else {
                            return null;
                        }
                    }
                }
                @Override
                public Map<TypeParameter, ProducedType> initTypeArguments() {
                    return emptyMap();
                }
            };
            that.setTypeModel(t);
        }
    }

    public void visit(Tree.GroupedType that) {
        super.visit(that);
        Tree.StaticType type = that.getType();
        if (type!=null) {
          that.setTypeModel(type.getTypeModel());
        }
    }
   
    @Override
    public void visit(Tree.ExtendedType that) {
        inExtends = true;
        super.visit(that);
        inExtends = false;
        TypeDeclaration td = (TypeDeclaration) that.getScope();
        if (td.isAlias()) {
            return;
        }
        if (that.getType()==null) {
            that.addError("missing extended type");
        }
        else if (that.getInvocationExpression()==null) {
            that.addError("missing instantiation arguments");
        }
        else {
            ProducedType type = that.getType().getTypeModel();
            if (type!=null) {
                td.setExtendedType(type);
            }
        }
    }
   
    @Override
    public void visit(Tree.SatisfiedTypes that) {
        inExtends = true;
        super.visit(that);
        inExtends = false;
        TypeDeclaration td = (TypeDeclaration) that.getScope();
        if (td.isAlias()) {
            return;
        }
        for (Tree.StaticType t: that.getTypes()) {
            if (t!=null) {
                ProducedType type = t.getTypeModel();
                if (type!=null) {
                    td.getSatisfiedTypes().add(type);
                }
            }
        }
    }
   
    @Override
    public void visit(Tree.ClassSpecifier that) {
        inExtends = true;
        super.visit(that);
        inExtends = false;
        if (that.getType()==null) {
            that.addError("missing aliased type");
        }
        else if (that.getInvocationExpression()==null) {
            that.addError("missing instantiation arguments");
        }
        else {
            TypeDeclaration td = (TypeDeclaration) that.getScope();
            ProducedType type = that.getType().getTypeModel();
            if (type!=null) {
                td.setExtendedType(type);
            }
            if (that.getMainToken().getType()==SPECIFY) {
                that.addError("incorrect syntax: aliased class must be specified using =>", 1050);
            }
        }
    }
   
    @Override
    public void visit(Tree.TypeSpecifier that) {
        inExtends = true;
        super.visit(that);
        inExtends = false;
        if (that.getType()==null) {
            that.addError("missing aliased type");
        }
        else if (!(that instanceof Tree.DefaultTypeArgument)) {
            TypeDeclaration td = (TypeDeclaration) that.getScope();
            ProducedType type = that.getType().getTypeModel();
            if (type!=null) {
                td.setExtendedType(type);
            }
            if (that.getMainToken().getType()==SPECIFY) {
                that.addError("incorrect syntax: aliased type must be specified using =>", 1050);
            }
        }
    }
   
    @Override
    public void visit(Tree.LazySpecifierExpression that) {
        super.visit(that);
        if (that.getMainToken().getType()==SPECIFY) {
            that.addError("incorrect syntax: expression must be specified using =>", 1050);
        }
    }
   
}
TOP

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

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.