package ceylon.language.meta;

import static com.redhat.ceylon.compiler.java.runtime.metamodel.Metamodel.getReflectedAnnotationClass;
import ceylon.language.Annotated;
import ceylon.language.Annotation;
import ceylon.language.AssertionError;
import ceylon.language.ConstrainedAnnotation;
import ceylon.language.OptionalAnnotation;
import ceylon.language.Sequence;
import ceylon.language.Sequential;
import ceylon.language.meta.model.Class;

import com.redhat.ceylon.compiler.java.metadata.Annotations;
import com.redhat.ceylon.compiler.java.metadata.Ceylon;
import com.redhat.ceylon.compiler.java.metadata.Ignore;
import com.redhat.ceylon.compiler.java.metadata.Method;
import com.redhat.ceylon.compiler.java.metadata.Name;
import com.redhat.ceylon.compiler.java.metadata.TypeInfo;
import com.redhat.ceylon.compiler.java.metadata.TypeParameter;
import com.redhat.ceylon.compiler.java.metadata.TypeParameters;
import com.redhat.ceylon.compiler.java.metadata.Variance;
import com.redhat.ceylon.compiler.java.runtime.metamodel.Metamodel;
import com.redhat.ceylon.compiler.java.runtime.model.TypeDescriptor;

@Ceylon(major = 8)
@Method
public final class annotations_ {
    
    private annotations_() {}
    
    // TODO @Shared$annotation
    @SuppressWarnings({ "unchecked" })
    @Annotations({@com.redhat.ceylon.compiler.java.metadata.Annotation("shared")})
    @TypeInfo("Values")
    @TypeParameters({
        @TypeParameter(value = "Value", 
                satisfies = {"ceylon.language::ConstrainedAnnotation<Value,Values,ProgramElement>"}), 
        @TypeParameter(value = "Values"), 
        @TypeParameter(value = "ProgramElement", 
                satisfies = {"ceylon.language::Annotated"}, 
                variance=Variance.IN)
    })
    public static <Value extends ConstrainedAnnotation
                          <? extends Value, 
                           ? extends Values, 
                           ? super ProgramElement>, 
                   Values, 
                   ProgramElement extends Annotated>
    Values annotations(
            @Ignore
            final TypeDescriptor $reifiedValue, 
            @Ignore
            final TypeDescriptor $reifiedValues, 
            @Ignore
            final TypeDescriptor $reifiedProgramElement, 
            @Name("annotationType")
            @TypeInfo("ceylon.language.meta.model::Class<ceylon.language::ConstrainedAnnotation<Value,Values,ProgramElement>,ceylon.language::Nothing>")
            final Class<? extends ConstrainedAnnotation
                    <? extends Value, 
                     ? extends Values, 
                     ? super ProgramElement>,
                     ?> 
            annotationType, 
            @Name("programElement")
            @TypeInfo("ProgramElement")
            final ProgramElement programElement) {
        Sequential<? extends Annotation> results = 
                Metamodel.annotations($reifiedValue, programElement);
        boolean optional = OptionalAnnotation.class
        		.isAssignableFrom(getReflectedAnnotationClass(annotationType));
		if (optional) {
            if (results.getSize() > 1L) {
                throw new AssertionError("optional annotation occurs more than once");
            }
            Object singleResult = 
                    results instanceof Sequence ? 
                            ((Sequence<?>) results).getFirst() : 
                            null;
            return (Values) singleResult;   
        }
        else {
            return (Values) results;
        }
    }
}
@@ -1766,32 +1766,48 @@
  %3CValue extends 
+ceylon.language.
 ConstrainedAnnot
@@ -1815,199 +1815,76 @@
 tion
-%0A                          %3C? extends Value, %0A                           ? extends Values, %0A                           ? super ProgramElement%3E, %0A                   Values, %0A                  
+%3C? extends Value, ? extends Values, ? super ProgramElement%3E, Values,
  Pro
@@ -1899,24 +1899,40 @@
 ent extends 
+ceylon.language.
 Annotated%3E%0A 
@@ -1929,21 +1929,16 @@
 notated%3E
-%0A    
 Values a
@@ -1952,47 +1952,121 @@
 ons(
-%0A            @Ignore%0A            final 
+@com.redhat.ceylon.compiler.java.metadata.Ignore%0A            final com.redhat.ceylon.compiler.java.runtime.model.
 Type
@@ -2088,54 +2088,129 @@
 fied
+$
 Value, 
-%0A            @Ignore%0A            final 
+@com.redhat.ceylon.compiler.java.metadata.Ignore%0A            final com.redhat.ceylon.compiler.java.runtime.model.
 Type
@@ -2228,24 +2228,25 @@
 $reified
+$
 Values, 
 %0A       
@@ -2241,47 +2241,121 @@
 es, 
-%0A            @Ignore%0A            final 
+@com.redhat.ceylon.compiler.java.metadata.Ignore%0A            final com.redhat.ceylon.compiler.java.runtime.model.
 Type
@@ -2373,16 +2373,17 @@
 $reified
+$
 ProgramE
@@ -2394,67 +2394,165 @@
 nt, 
-%0A            @Name(%22annotationType%22)%0A            @TypeInfo(
+@com.redhat.ceylon.compiler.java.metadata.Name(%22annotationType%22)%0A            @com.redhat.ceylon.compiler.java.metadata.TypeInfo(%0A                    value = 
 %22cey
@@ -2676,17 +2676,17 @@
 othing%3E%22
-)
+,
 %0A       
@@ -2694,231 +2694,235 @@
     
-final Class%3C? extends ConstrainedAnnotation%0A                    %3C? extends Value, %0A                     ? extends Values, %0A                     ? super ProgramElement%3E,%0A                     ?%3E %0A            annotationType, %0A
+        erased = true)%0A            final ceylon.language.meta.model.Class annotationType, @com.redhat.ceylon.compiler.java.metadata.Name(%22programElement%22)%0A            @com.redhat.ceylon.compiler.java.metadata.TypeInfo(%0A        
     
@@ -2933,16 +2933,18 @@
     
-@Name(%22p
+value = %22P
 rogr
@@ -2945,33 +2945,33 @@
 %22ProgramElement%22
-)
+,
 %0A            @Ty
@@ -2971,34 +2971,29 @@
     
-@TypeInfo(%22ProgramElement%22
+        erased = true
 )%0A  
@@ -3089,24 +3089,24 @@
  results = %0A
-
             
@@ -3139,16 +3139,17 @@
 $reified
+$
 Value, p

Fix ceylon/ceylon-compiler#2029 but updating the signature of annotations() to be the same as what the compiler would generate.