void ParameterizeBaseType(DataType current, Dictionary <DataType, DataType> map, DataType result) { current.AssignBaseType(); result.SetBase(ParameterizeType(map, current.Base)); if (result is DelegateType) { var currentDelegate = (DelegateType)current; var resultDelegate = (DelegateType)result; resultDelegate.SetReturnType(ParameterizeType(map, currentDelegate.ReturnType)); resultDelegate.SetParameters(ParameterizeParameters(map, currentDelegate.Parameters)); } else if (current.Interfaces.Length > 0) { var interfaceTypes = new InterfaceType[current.Interfaces.Length]; for (int i = 0, l = interfaceTypes.Length; i < l; i++) { interfaceTypes[i] = (InterfaceType)ParameterizeType(map, current.Interfaces[i]); } result.SetInterfaces(interfaceTypes); } }
Expression TryCompileCast(Source src, DataType targetType, Expression operand) { if (targetType.IsInvalid || operand.IsInvalid) { return(Expression.Invalid); } // Equal types == NOP if (targetType.Equals(operand.ReturnType)) { return(operand); } var cast = TryResolveCastOverload(src, NameResolver.GetTypeCasts(targetType, operand.ReturnType), ref operand); if (cast != null) { return(new CallCast(src, cast, operand)); } // Box // Generic -> object // Method -> delegate // etc var impl = TryCompileImplicitCast(src, targetType, operand); if (impl != null) { return(impl); } // Down cast if (targetType.IsReferenceType && operand.ReturnType.IsReferenceType || targetType.IsInterface || operand.ReturnType.IsInterface) { return(operand.ReturnType.IsInterface || operand.ReturnType.IsSubclassOf(targetType) || operand.ReturnType.IsImplementingInterface(targetType) || targetType.IsInterface || targetType.IsSubclassOf(operand.ReturnType) || targetType.IsImplementingInterface(operand.ReturnType) ? new CastOp(src, targetType, operand) : Error(src, ErrorCode.E2028, targetType.Quote() + " and " + operand.ReturnType.Quote() + " are not compatible types")); } // Unbox // Ref -> generic if (targetType.IsValueType && operand.ReturnType.Equals(Essentials.Object) || targetType.IsGenericParameter && operand.ReturnType.IsReferenceType) { return(new CastOp(src, targetType, operand)); } if (operand.ReturnType.IsEnum) { operand.ReturnType.AssignBaseType(); return(TryCompileCast(src, targetType, new CastOp(src, operand.ReturnType.Base ?? Essentials.Int, operand))); } if (targetType.IsEnum) { targetType.AssignBaseType(); var intValue = TryCompileCast(src, targetType.Base ?? Essentials.Int, operand); if (intValue != null) { return(new CastOp(src, targetType, intValue)); } } return(null); }
Expression TryCompileImplicitCast(Source src, DataType expectedType, Expression value, bool reportErrorIfNotFound) { if (ImplicitCastStack.Contains(expectedType)) { ImplicitCastStack.Add(expectedType); } else { ImplicitCastStack.Add(expectedType); if (Equals(expectedType, value.ReturnType)) { return(value); } if (value.ReturnType is InvalidType || expectedType is InvalidType) { return(Expression.Invalid); } // (EnumType)0 if (expectedType is EnumType && value is Constant && value.ConstantValue is int && (int)value.ConstantValue == 0) { return(new Constant(value.Source, (EnumType)expectedType, (int)value.ConstantValue)); } // Null type (must be done before delegate) if (value.ReturnType.IsNull) { return(expectedType.IsReferenceType ? new Constant(src, expectedType, null) : !reportErrorIfNotFound ? null : Error(src, ErrorCode.E2043, "'<null>' has no implicit cast to " + expectedType.Quote() + " because that is not a reference type")); } // Delegate if (expectedType is DelegateType && value is MethodGroup) { var dt = expectedType as DelegateType; dt.AssignBaseType(); var mg = value as MethodGroup; var candidates = mg.Candidates; var compatibleMethods = new List <Method>(); foreach (var m in candidates) { if (!m.IsGenericDefinition && m.ReturnType.Equals(dt.ReturnType) && dt.CompareParameters(m)) { compatibleMethods.Add(m); } } if (compatibleMethods.Count == 0) { foreach (var c in candidates) { if (c.IsGenericDefinition) { var dummyArgs = new Expression[dt.Parameters.Length]; for (int i = 0; i < dummyArgs.Length; i++) { var p = dt.Parameters[i]; dummyArgs[i] = new Default(p.Source, p.Type); switch (p.Modifier) { case ParameterModifier.Const: dummyArgs[i] = new AddressOf(dummyArgs[i], AddressType.Const); break; case ParameterModifier.Ref: dummyArgs[i] = new AddressOf(dummyArgs[i], AddressType.Ref); break; case ParameterModifier.Out: dummyArgs[i] = new AddressOf(dummyArgs[i], AddressType.Out); break; } } candidates = CopyAndParameterizeGenericMethods(src, candidates, dummyArgs); foreach (var m in candidates) { if (!m.IsGenericDefinition && m.ReturnType.Equals(dt.ReturnType) && dt.CompareParameters(m)) { compatibleMethods.Add(m); } } break; } } if (compatibleMethods.Count == 0) { foreach (var m in candidates) { if (!m.IsGenericDefinition && (m.ReturnType.Equals(dt.ReturnType) || m.ReturnType.IsReferenceType && m.ReturnType.IsSubclassOfOrEqual(dt.ReturnType)) && dt.CompareParametersEqualOrSubclassOf(m)) { compatibleMethods.Add(m); } } } } if (compatibleMethods.Count == 1) { var m = compatibleMethods[0]; if (m.IsStatic) { return(new NewDelegate(src, dt, null, m)); } if (mg.Object != null && !mg.Object.ReturnType.IsReferenceType) { mg.Object = new CastOp(src, Essentials.Object, mg.Object.ActualValue); } return(new NewDelegate(src, dt, mg.Object, m)); } return(!reportErrorIfNotFound ? null : compatibleMethods.Count == 0 ? Error(src, ErrorCode.E2045, "No methods matches the parameter list and return type of delegate type " + dt.Quote()) : ReportAmbiguousMatchError(src, compatibleMethods)); } // Lambda if (expectedType is DelegateType && value is UncompiledLambda) { expectedType.AssignBaseType(); return(TryCompileImplicitLambdaCast((UncompiledLambda)value, (DelegateType)expectedType)); } // Constant if (value is Constant && expectedType.IsIntrinsic) { var constant = value as Constant; if (constant.Value is int) { int intValue = (int)constant.Value; switch (expectedType.BuiltinType) { case BuiltinType.SByte: if (intValue >= -0x80 && intValue <= 0x7f) { return(new Constant(constant.Source, expectedType, (sbyte)intValue)); } break; case BuiltinType.Byte: if (intValue >= 0 && intValue <= 0xff) { return(new Constant(constant.Source, expectedType, (byte)intValue)); } break; case BuiltinType.Short: if (intValue >= -0x8000 && intValue <= 0x7fff) { return(new Constant(constant.Source, expectedType, (short)intValue)); } break; case BuiltinType.UShort: if (intValue >= 0 && intValue <= 0xffff) { return(new Constant(constant.Source, expectedType, (ushort)intValue)); } break; case BuiltinType.UInt: if (intValue >= 0) { return(new Constant(constant.Source, expectedType, (uint)intValue)); } break; case BuiltinType.ULong: if (intValue >= 0) { return(new Constant(constant.Source, expectedType, (ulong)intValue)); } break; } } if (constant.Value is long) { long longValue = (long)constant.Value; switch (expectedType.BuiltinType) { case BuiltinType.ULong: if (longValue >= 0) { return(new Constant(constant.Source, expectedType, (ulong)longValue)); } break; } } } // Implict cast bool ambiguous; var cast = TryResolveCastOverload(src, NameResolver.GetTypeCasts(expectedType, value.ReturnType), ref value, reportErrorIfNotFound, out ambiguous); if (ambiguous) { goto ERROR; } if (cast != null && cast.IsImplicitCast) { return(new CallCast(src, cast, value)); } // Up cast if (expectedType == Essentials.Object || value.ReturnType.IsSubclassOf(expectedType) || expectedType.IsInterface && value.ReturnType.IsImplementingInterface(expectedType)) { return(new CastOp(src, expectedType, value)); } // Fixed Array if (expectedType.IsFixedArray && value.ReturnType.IsFixedArray) { var t1 = expectedType as FixedArrayType; var t2 = value.ReturnType as FixedArrayType; if (t1.ElementType.Equals(t2.ElementType) && ( t1.OptionalSize == null || t2.OptionalSize == null || t1.OptionalSize is Constant && t2.OptionalSize is Constant && Equals(t1.OptionalSize.ConstantValue, t2.OptionalSize.ConstantValue) )) { return(value); } } // T[] -> IEnumerable<T> if (value.ReturnType.IsRefArray && expectedType.MasterDefinition == Essentials.IEnumerable_T) { ImplicitCastStack.RemoveLast(); var arrayEnumerable = TypeBuilder.Parameterize(src, Essentials.ArrayEnumerable_T, value.ReturnType.ElementType); return(TryCompileImplicitCast(src, expectedType, ILFactory.NewObject(src, arrayEnumerable, value), reportErrorIfNotFound)); } } ERROR: return(!reportErrorIfNotFound ? null : Error(src, ErrorCode.E2047, "No implicit cast from " + value.ReturnType.Quote() + " to " + expectedType.Quote())); }
void ParameterizeMembers(DataType definition, DataType current, Dictionary <DataType, DataType> map, DataType result) { current.AssignAttributes(); result.SetAttributes(current.Attributes); current.PopulateMembers(); foreach (var s in current.Swizzlers) { result.Swizzlers.Add(ParameterizeType(map, s)); } if (current.Initializer != null) { var m = current.Initializer; var c = new Constructor(m.Source, result, m.DocComment, m.Modifiers, ParameterizeParameters(map, m.Parameters), m.Body); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Initializer = c; } if (current.Finalizer != null) { var m = current.Finalizer; var c = new Finalizer(m.Source, result, m.DocComment, m.Modifiers, ParameterizeParameters(map, m.Parameters), m.Body); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Finalizer = c; } foreach (var m in current.Constructors) { var c = new Constructor(m.Source, result, m.DocComment, m.Modifiers, ParameterizeParameters(map, m.Parameters), m.Body); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Constructors.Add(c); } foreach (var m in current.Methods) { DataType owner = result; ClassType genericMethodParametersOwner = null; if (m.IsGenericDefinition) { if (m.GenericType != definition) { genericMethodParametersOwner = new ClassType(m.Source, result, m.DocComment, Modifiers.Private | Modifiers.Static | Modifiers.Generated, m.UnoName); genericMethodParametersOwner.MakeGenericDefinition(m.GenericParameters); foreach (var p in m.GenericParameters) { map.Add(p, p); } } else { owner = (DataType)result.Parent; genericMethodParametersOwner = (ClassType)result; } } var c = new Method(m.Source, owner, m.DocComment, m.Modifiers, m.UnoName, genericMethodParametersOwner, ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters), m.Body); if (genericMethodParametersOwner != null && genericMethodParametersOwner != result) { genericMethodParametersOwner.Methods.Add(c); } if (m.OverriddenMethod != null) { c.SetOverriddenMethod(ParameterizeMethod(map, m.OverriddenMethod)); } if (m.ImplementedMethod != null) { c.SetImplementedMethod(ParameterizeMethod(map, m.ImplementedMethod)); } m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Methods.Add(c); } foreach (var m in current.Properties) { var c = new Property(m.Source, m.DocComment, m.Modifiers, m.UnoName, result, ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters)); if (m.GetMethod != null) { c.CreateGetMethod(m.GetMethod.Source, m.GetMethod.Modifiers, m.GetMethod.Body); } if (m.SetMethod != null) { c.CreateSetMethod(m.SetMethod.Source, m.SetMethod.Modifiers, m.SetMethod.Body); } if (m.ImplicitField != null) { c.CreateImplicitField(m.ImplicitField.Source); } if (m.OverriddenProperty != null) { c.SetOverriddenProperty(ParameterizeProperty(map, m.OverriddenProperty)); } if (m.ImplementedProperty != null) { c.SetImplementedProperty(ParameterizeProperty(map, m.ImplementedProperty)); } m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Properties.Add(c); } foreach (var m in current.Events) { var c = new Event(m.Source, m.DocComment, m.Modifiers, result, ParameterizeType(map, m.ReturnType), m.UnoName); if (m.AddMethod != null) { c.CreateAddMethod(m.AddMethod.Source, m.AddMethod.Modifiers, m.AddMethod.Body); } if (m.RemoveMethod != null) { c.CreateRemoveMethod(m.RemoveMethod.Source, m.RemoveMethod.Modifiers, m.RemoveMethod.Body); } if (m.ImplicitField != null) { c.CreateImplicitField(m.ImplicitField.Source); } if (m.OverriddenEvent != null) { c.SetOverriddenEvent(ParameterizeEvent(map, m.OverriddenEvent)); } if (m.ImplementedEvent != null) { c.SetImplementedEvent(ParameterizeEvent(map, m.ImplementedEvent)); } m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Events.Add(c); } foreach (var m in current.Casts) { var c = new Cast(m.Source, result, m.Type, m.DocComment, m.Modifiers, ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters), m.Body); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Casts.Add(c); } foreach (var m in current.Operators) { var c = new Operator(m.Source, result, m.Type, m.DocComment, m.Modifiers, ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters), m.Body); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Operators.Add(c); } foreach (var m in current.Fields) { var c = new Field(m.Source, result, m.UnoName, m.DocComment, m.Modifiers, m.FieldModifiers, ParameterizeType(map, m.ReturnType)); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Fields.Add(c); } foreach (var m in current.Literals) { var c = new Literal(m.Source, result, m.UnoName, m.DocComment, m.Modifiers, ParameterizeType(map, m.ReturnType), m.Value); m.AssignAttributes(); c.SetAttributes(m.Attributes); c.SetMasterDefinition(m.MasterDefinition); result.Literals.Add(c); } result.AssignBaseType(); if (!result.IsParameterizedDefinition && !result.IsInterface && result.Interfaces.Length > 0) { foreach (var e in current.InterfaceMethods) { var impl = FindParameterizedMethod(ParameterizeType(map, e.Key.DeclaringType), e.Key); var decl = FindParameterizedMethod(result, e.Value); result.InterfaceMethods[impl] = decl; } } }