예제 #1
0
        public static Annotation GetGenericDefinitionAnnotationForType(XTypeReference xtype, bool forceTypeDefinition, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            var genericsDefAnnotationClass = compiler.GetDot42InternalType(InternalConstants.GenericDefinitionAnnotation)
                                                     .GetClassReference(targetPackage);
            var annotation = new Annotation {Type = genericsDefAnnotationClass, Visibility = AnnotationVisibility.Runtime};

            if (xtype.IsGenericInstance)
            {
                bool handled = false;
                List<object> genericArguments = new List<object>();

                if (xtype.GetElementType().IsNullableT())
                {
                    // privitives and enums are represented by their marker classes. 
                    // no annotation needed.
                    var argument = ((XGenericInstanceType) xtype).GenericArguments[0];
                    if (argument.IsEnum() || argument.IsPrimitive && !forceTypeDefinition)
                    {
                        return null;
                    }
                        
                    // structs have marker classes.
                    var classRef = xtype.GetReference(targetPackage) as ClassReference;
                    var @class = classRef == null ? null : targetPackage.DexFile.GetClass(classRef.Fullname);
                    if (@class != null && @class.NullableMarkerClass != null)
                    {
                        annotation.Arguments.Add(new AnnotationArgument("GenericInstanceType", @class.NullableMarkerClass));
                        handled = true;
                    }
                }

                if (!handled)
                {
                    foreach (var arg in ((XGenericInstanceType) xtype).GenericArguments)
                    {
                        if (arg.IsGenericParameter)
                        {
                            var gparm = (XGenericParameter) arg;

                            // TODO: if we wanted to annotate methods as well, we should differentiate 
                            //       between generic method arguments and generic type arguments.

                            genericArguments.Add(gparm.Position);
                        }
                        else if (arg.IsGenericInstance)
                        {
                            var giparm = GetGenericDefinitionAnnotationForType((XGenericInstanceType) arg, true,compiler, targetPackage);
                            genericArguments.Add(giparm);
                        }
                        else
                        {
                            genericArguments.Add(arg.GetReference(targetPackage));
                        }
                    }
                    annotation.Arguments.Add(new AnnotationArgument("GenericArguments", genericArguments.ToArray()));
                }
            }
            else // generic parameter
            {
                var parm = (XGenericParameter) xtype;
                annotation.Arguments.Add(new AnnotationArgument("GenericParameter", parm.Position));
            }

            if(forceTypeDefinition && annotation.Arguments.All(a => a.Name != "GenericInstanceType"))
                annotation.Arguments.Add(new AnnotationArgument("GenericTypeDefinition", xtype.ElementType.GetReference(targetPackage)));

            return annotation;
        }
예제 #2
0
        /// <summary>
        /// Create an expression that loads the given type at runtime.
        /// </summary>
        private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod, 
                    XTypeReference type, AssemblyCompiler compiler, XTypeDefinition typeHelperType, XTypeSystem typeSystem, 
                    TypeConversion typeConversion, XGenericInstanceType typeGenericArguments=null)
        {
            if (type.IsArray)
            {
                // Array type
                var arrayType = (XArrayType)type;
                // Load element type
                var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, compiler, typeHelperType, typeSystem, typeConversion);
                // Convert to array type
                if (arrayType.Dimensions.Count() == 1)
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1));
                    return new AstExpression(seqp, AstCode.Call, giCreateArray, prefix) { ExpectedType = typeSystem.Type };
                }
                else
                {
                    var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2));
                    var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count()) { ExpectedType = typeSystem.Int };
                    return new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr) { ExpectedType = typeSystem.Type };
                }
            }

            var gp = type as XGenericParameter;
            if (gp != null)
            {
                AstExpression loadExpr;
                if (gp.Owner is XTypeReference)
                {
                    // Class type parameter
                    var owner = (XTypeReference)gp.Owner;
                    if (owner.GetElementType().Resolve().HasDexImportAttribute())
                    {
                        // Imported type
                        return new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type };
                    }
                    if (currentMethod.IsClassCtor)
                    {
                        // Class ctor's cannot have type information.
                        // Return Object instead
                        if(currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("StaticConstructorUsesGenericParameter"))
                        {
                            var msg = "Class (static) constructor of '{0}' tries to use generic parameter. This will always yield Object. " +
                                      "You can suppress this warning with a [SuppressMessage(\"dot42\", \"StaticConstructorUsesGenericParameter\")] " +
                                      "attribute on the class.";

                            if(seqp != null && seqp.Document != null)
                                DLog.Warning(DContext.CompilerCodeGenerator, seqp.Document, seqp.StartColumn,seqp.StartLine, msg, currentMethod.DeclaringTypeFullName);
                            else
                                DLog.Warning(DContext.CompilerCodeGenerator, msg, currentMethod.DeclaringTypeFullName);
                        }
                        return new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type };
                    }
                    loadExpr = currentMethod.IsStatic ?
                        LoadStaticClassGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position) :
                        LoadInstanceClassGenericArgument(seqp, typeSystem, currentMethod.Method.DeclaringType, gp.Position);
                }
                else
                {
                    // Method type parameter
                    var owner = (XMethodReference)gp.Owner;
                    if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute())
                    {
                        // Imported type
                        return LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, compiler, typeHelperType, typeSystem, typeConversion);
                    }
                    loadExpr = LoadMethodGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position);
                }

                if (typeConversion == TypeConversion.EnsureRuntimeType)
                    return EnsureGenericRuntimeType(loadExpr, typeSystem, typeHelperType);
                else
                    return loadExpr;
            }

            if (type is XTypeSpecification)
            {
                var typeSpec = (XTypeSpecification)type;
                var git = type as XGenericInstanceType;
                var baseType = LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, compiler, typeHelperType, typeSystem, typeConversion, git);

                if (typeConversion != TypeConversion.EnsureTrueOrMarkerType || typeSpec.GetElementType().IsNullableT())
                    return baseType;

                // Use the element type and make a generic proxy with the generic arguments.
                var parameters = CreateGenericInstanceCallArguments(seqp, git, currentMethod, compiler);
                if (parameters.Count == 1 && parameters[0].GetResultType().IsArray)
                {
                    // array type call.
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == 2 && m.Parameters[1].ParameterType.IsArray);
                    return new AstExpression(seqp, AstCode.Call, method, baseType, parameters[0]);
                }
                else
                {
                    parameters.Insert(0, baseType);
                    var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == parameters.Count && !m.Parameters[1].ParameterType.IsArray);
                    return new AstExpression(seqp, AstCode.Call, method, parameters.ToArray());
                }
            }


            if (typeConversion == TypeConversion.EnsureTrueOrMarkerType && type.GetElementType().IsNullableT())
            {
                if (typeGenericArguments != null)
                {
                    var underlying = typeGenericArguments.GenericArguments[0];
                    var code = underlying.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf;
                    return new AstExpression(seqp, code, underlying) { ExpectedType = typeSystem.Type };
                }
                // if typeGenericArguments is null, this is a generic definition, e.g. typeof(Nullable<>).
            }

            // Plain type reference or definition
            return new AstExpression(seqp, AstCode.TypeOf, type) { ExpectedType = typeSystem.Type };
        }
예제 #3
0
 /// <summary>
 /// Gets the deepest <see cref="XTypeReference.ElementType"/>.
 /// </summary>
 public override XTypeReference GetElementType()
 {
     return(elementType.GetElementType());
 }
        /// <summary>
        /// The syntax is experimental, and neither fully fixed nor officially defined.
        /// </summary>
        private static string GetDefinition(XTypeReference xtype, bool forceTypeDefinition, AssemblyCompiler compiler,
            DexTargetPackage targetPackage)
        {
            StringBuilder s = new StringBuilder();

            // TODO: reorganize, so that the syntax becomes clear.

            bool setGenericInstanceType = false;

            if (xtype.IsGenericInstance)
            {
                bool handled = false;

                if (xtype.GetElementType().IsNullableT())
                {
                    // privitives and enums are represented by their marker classes. 
                    // no annotation needed.
                    var argument = ((XGenericInstanceType) xtype).GenericArguments[0];
                    if (!forceTypeDefinition && (argument.IsEnum() || argument.IsPrimitive))
                    {
                        return "";
                    }

                    // structs have marker classes.
                    var classRef = xtype.GetReference(targetPackage) as ClassReference;
                    var @class = classRef == null ? null : targetPackage.DexFile.GetClass(classRef.Fullname);
                    if (@class != null && @class.NullableMarkerClass != null)
                    {
                        s.Append("@");
                        s.Append(GetClassName(@class.NullableMarkerClass));
                        setGenericInstanceType = true;
                        handled = true;
                    }
                }

                if (!handled)
                {
                    bool isFirst = true;
                    foreach (var arg in ((XGenericInstanceType) xtype).GenericArguments)
                    {
                        if (!isFirst) s.Append(",");
                        isFirst = false;

                        if (arg.IsGenericParameter)
                        {
                            var gparm = (XGenericParameter) arg;

                            // TODO: if we wanted to annotate methods as well, we should differentiate 
                            //       between generic method arguments and generic type arguments.
                            s.Append("!");
                            s.Append(gparm.Position);
                        }
                        else if (arg.IsGenericInstance)
                        {
                            var giparm = GetDefinition((XGenericInstanceType)arg, true, compiler, targetPackage);
                            s.Append("{");
                            s.Append(giparm);
                            s.Append("}");
                        }
                        else
                        {
                            s.Append(GetClassName(arg.GetReference(targetPackage)));
                        }
                    }
                }
            }
            else // generic parameter
            {
                var parm = (XGenericParameter) xtype;
                s.Append("!!");
                s.Append(parm.Position);
            }

            if (forceTypeDefinition && !setGenericInstanceType)
            {
                string def = GetClassName(xtype.ElementType.GetReference(targetPackage));
                s.Insert(0, def + "<");
                s.Append(">");
            }

            return s.ToString();
        }