    import ceylon.language.meta.model {
        ClassOrInterface,
        Member,
        AppliedType = Type,
        IncompatibleTypeException,
        TypeApplicationException
    }

    """A class or interface declaration.

       <a name="toplevel-sample"></a>
       ### Usage sample for toplevel classes

       Because some classes have type parameters, getting a model requires applying type arguments to the
       class declaration with [[apply]] in order to be able to instantiate that class. For example, here is how you would
       obtain a class or interface model that you can instantiate from a toplevel class declaration:

           class Foo<T>() {
               string => "Hello, our T is: ``typeLiteral<T>()``";
           }

           void test(){
               // We need to apply the Integer closed type to the Foo declaration in order to get the Foo<Integer> closed type
               ClassOrInterface<Foo<Integer>> classOrInterfaceModel = `class Foo`.apply<Foo<Integer>>(`Integer`);
               assert(is Class<Foo<Integer>,[]> classOrInterfaceModel);
               // This will print: Hello, our T is: ceylon.language::Integer
               print(classOrInterfaceModel());
           }

       Note that there are more specialised versions of [[apply]] in [[ClassDeclaration.classApply]] and
       [[InterfaceDeclaration.interfaceApply]].

       <a name="member-sample"></a>
       ### Usage sample for member classes

       For member classes or interfaces it is a bit longer, because member types need to be applied not only their type arguments but also
       the containing type, so you should use [[memberApply]] and start by giving the containing closed type:

           class Outer(){
               shared class Inner(){
                   string => "Hello";
               }
           }

           void test(){
               // apply the containing closed type `Outer` to the member class declaration `Outer.Inner`
               value memberClassModel = `class Outer.Inner`.memberApply<Outer,Outer.Inner>(`Outer`);
               assert(is MemberClass<Outer,Outer.Inner,[]> memberClassModel);
               // We now have a MemberClass, which needs to be applied to a containing instance in order to become an
               // invokable class model:
               Class<Outer.Inner,[]> boundMemberClassModel = memberClassModel(Outer());
               // This will print: Hello
               print(boundMemberClassModel());
           }

       Note that there are more specialised versions of [[memberApply]] in [[ClassDeclaration.memberClassApply]] and
       [[InterfaceDeclaration.memberInterfaceApply]].
       """
    shared interface ClassOrInterfaceDeclaration
            of ClassDeclaration | InterfaceDeclaration
            satisfies NestableDeclaration & GenericDeclaration {

        "This type's extended type, unless this is the class for [[Anything|ceylon.language::Anything]], which
         is the root of the type hierarchy and thus does not have any extended type."
        shared formal OpenClassType? extendedType;

        "The list of types satisfied by this type."
        shared formal OpenInterfaceType[] satisfiedTypes;

        "If this type has an `of` clause, this is the list of case types for the current type."
        shared formal OpenType[] caseTypes;

        "True if this type is an alias type, in which case the [[extendedType]] will
         contain the substituted type."
        shared formal Boolean isAlias;

        // FIXME: should Kind default to NestableDeclaration?
        "Returns the list of member declarations that satisfy the given `Kind` type argument."
        shared formal Kind[] memberDeclarations<Kind>()
                given Kind satisfies NestableDeclaration;

        "Returns the list of member declarations that satisfy the given `Kind` type argument."
        shared formal Kind[] declaredMemberDeclarations<Kind>()
            given Kind satisfies NestableDeclaration;

        "Returns the list of member declarations that satisfy the given `Kind` type argument and
         that are annotated with the given `Annotation` type argument"
        shared formal Kind[] annotatedMemberDeclarations<Kind, Annotation>()
            given Kind satisfies NestableDeclaration;

        "Returns the list of member declarations that satisfy the given `Kind` type argument and
         that are annotated with the given `Annotation` type argument"
        shared formal Kind[] annotatedDeclaredMemberDeclarations<Kind, Annotation>()
                given Kind satisfies NestableDeclaration;

        "Looks up a member declaration by name, provided it satisfies the given `Kind` type
         argument. Returns `null` if no such member matches."
        shared formal Kind? getMemberDeclaration<Kind>(String name)
                given Kind satisfies NestableDeclaration;

        "Looks up a member declaration by name, provided it satisfies the given `Kind` type
         argument. Returns `null` if no such member matches."
        shared formal Kind? getDeclaredMemberDeclaration<Kind>(String name)
            given Kind satisfies NestableDeclaration;

        "Applies the given closed type arguments to this toplevel class or interface declaration in order to obtain a class or interface model.
         See [this code sample](#toplevel-sample) for an example on how to use this."
        throws(`class IncompatibleTypeException`, "If the specified `Type` type argument is not compatible with the actual result.")
        throws(`class TypeApplicationException`, "If the specified closed type argument values are not compatible with the actual result's type parameters.")
        shared formal ClassOrInterface<Type> apply<Type=Anything>(AppliedType<Anything>* typeArguments);

        "Applies the given closed container type and type arguments to this member class or interface declaration in order to obtain a
         member class or interface model. See [this code sample](#member-sample) for an example on how to use this."
        throws(`class IncompatibleTypeException`, "If the specified `Container` or `Type` type arguments are not compatible with the actual result.")
        throws(`class TypeApplicationException`, "If the specified closed container type or type argument values are not compatible with the actual result's container type or type parameters.")
        shared formal Member<Container, ClassOrInterface<Type>> & ClassOrInterface<Type>
            memberApply<Container=Nothing, Type=Anything>(AppliedType<Container> containerType, AppliedType<Anything>* typeArguments);

    }