/// <summary> /// Is this generic parameter the same as the given other? /// </summary> public bool IsSame(XGenericInstanceType other) { if (!ElementType.IsSame(other.ElementType) || (GenericArguments.Count != other.GenericArguments.Count)) { return(false); } return(!GenericArguments.Where((t, i) => !t.IsSame(other.GenericArguments[i])).Any()); }
/// <summary> /// Is this generic parameter the same as the given other? /// </summary> public bool IsSame(XGenericInstanceType other) { if (!ElementType.IsSame(other.ElementType) || (GenericArguments.Count != other.GenericArguments.Count)) return false; return !GenericArguments.Where((t, i) => !t.IsSame(other.GenericArguments[i])).Any(); }
/// <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 }; }