edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/IronPython/Tests/test_peverify.py;C450364 File: test_peverify.py =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/IronPython/Tests/test_peverify.py;C450364 (server) 8/13/2008 7:15 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/IronPython/Tests/test_peverify.py;rubyclrinterop01 @@ -56,7 +56,7 @@ print "Error: ", output2 print -if ret == 1 and "Error Verifying" in output1: +if ret == 1 and ("Error Verifying" in output1 or "Error(s) Verifying" in output1): print "caught verification failure: pass" sys.exit(0) else: =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Marshal.cs;C518603 File: Marshal.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Marshal.cs;C518603 (server) 8/8/2008 1:13 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Marshal.cs;rubyclrinterop01 @@ -300,7 +300,11 @@ RubyClass theClass = _rubyContext.GetClassOf(obj); TestForAnonymous(theClass); WriteSymbol(theClass.Name); - WriteString(_DumpSite.Target(_DumpSite, _context, obj, _recursionLimit)); + MutableString dumpResult = (_DumpSite.Target(_DumpSite, _context, obj, _recursionLimit) as MutableString); + if (dumpResult == null) { + throw RubyExceptions.CreateTypeError("_dump() must return string"); + } + WriteString(dumpResult); } void WriteUsingMarshalDump(object/*!*/ obj) { =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyEncodingOps.cs;C525618 File: RubyEncodingOps.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyEncodingOps.cs;C525618 (server) 8/13/2008 8:53 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyEncodingOps.cs;rubyclrinterop01 @@ -42,7 +42,7 @@ [RubyMethod("inspect")] public static MutableString/*!*/ Inspect(CodeContext/*!*/ context, RubyEncoding/*!*/ self) { - // TODO: to_s overriden + // TODO: to_s overridden MutableString result = MutableString.CreateMutable(); result.Append("#<"); result.Append(RubyUtils.GetClassName(context, self)); =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C525618 File: Ruby.csproj =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C525618 (server) 8/4/2008 2:15 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;rubyclrinterop01 @@ -123,6 +123,7 @@ + @@ -312,4 +313,4 @@ mkdir "$(SolutionDir)..\..\Tools\Nessie\Nessie\bin\Debug" copy /y "$(TargetPath)" "$(SolutionDir)..\..\Tools\Nessie\Nessie\bin\Debug" - \ No newline at end of file + =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj.vspscc;C390406 edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs;C518603 File: RubyClass.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs;C518603 (server) 8/6/2008 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyClass.cs;rubyclrinterop01 @@ -48,7 +48,7 @@ private readonly object _singletonClassOf; // null for singletons: - private readonly Type _underlyingSystemType; + private Type _underlyingSystemType; private readonly bool _isRubyClass; private GlobalScopeExtension _globalScope; @@ -83,6 +83,10 @@ _globalScope = value; } + protected override bool CanIncludeClrInterface { + get { return !IsSingletonClass && (_underlyingSystemType == null); } + } + #if FALSE private Type _extensionType; @@ -102,6 +106,10 @@ throw new InvalidOperationException("Singleton class doesn't have underlying system type."); } + if (_underlyingSystemType == null) { + Interlocked.Exchange(ref _underlyingSystemType, RubyTypeBuilder.GetOrCreateType(_superClass.GetUnderlyingSystemType(), GetClrInterfaces())); + } + Debug.Assert(_underlyingSystemType != null); return _underlyingSystemType; } @@ -118,16 +126,16 @@ // friend: RubyExecutionContext // tracker: non-null => show members declared on the tracker internal RubyClass(RubyExecutionContext/*!*/ context, SymbolId name, Type type, object singletonClassOf, Action initializer, - RubyClass superClass, TypeTracker tracker, bool isRubyClass) + RubyClass superClass, TypeTracker tracker, bool isRubyClass, bool isSingletonClass) : base(context, name, initializer, null, tracker) { - + Debug.Assert((superClass == null) == (type == typeof(object)), "All classes have a superclass, except for Object"); Debug.Assert(!isRubyClass || tracker == null, "Ruby class cannot have a tracker"); - Debug.Assert(singletonClassOf != null || type != null, "Singleton classes don't have a type"); + Debug.Assert(singletonClassOf != null || !isSingletonClass, "Singleton classes don't have a type"); _underlyingSystemType = type; _superClass = superClass; - _isSingletonClass = type == null; + _isSingletonClass = isSingletonClass; _isRubyClass = isRubyClass; _singletonClassOf = singletonClassOf; @@ -157,10 +165,10 @@ // expect this type as "self" parameter (this is especially necessary for library types and types deriving from CLR types). // - MRI duplicates Object class so that the result doesn't inherit from Object, // which we don't do (we want our class hierarchy to be rooted). - Type type = RubyTypeBuilder.GetOrCreateType(GetUnderlyingSystemType()); + Type type = RubyTypeBuilder.GetOrCreateType(GetUnderlyingSystemType(), Type.EmptyTypes); RubyClass result = ExecutionContext.CreateClass(SymbolId.Empty, type, null, null, null, - _superClass ?? ExecutionContext.ObjectClass, null, true + _superClass ?? ExecutionContext.ObjectClass, null, true, false ); result.InitializeFrom(this); =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs;C518603 File: RubyModule.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs;C518603 (server) 8/6/2008 12:56 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs;rubyclrinterop01 @@ -61,7 +61,7 @@ // This is stored in the order that mixins are added, but // in the reverse order from how methods/constants are searched - private RubyModule[]/*!*/ _mixins; + private readonly List/*!*/ _mixins; private SymbolId _name; private State _state; @@ -158,7 +158,7 @@ _executionContext = context; _name = name; _state = State.Uninitialized; - _mixins = EmptyArray; + _mixins = new List(); _initializer = initializer; _version = Interlocked.Increment(ref _globalVersion); _clrConstants = clrConstants; @@ -182,7 +182,7 @@ _methods = new Dictionary(); Debug.WriteLine(SymbolTable.IdToString(_name) ?? "", "INITED"); - + _state = State.Initializing; try { if (_initializer != null) { @@ -196,7 +196,7 @@ internal virtual void EnsureInitialized() { if (_state == State.Uninitialized) { - for (int i = 0; i < _mixins.Length; i++) { + for (int i = 0; i < _mixins.Count; i++) { _mixins[i].EnsureInitialized(); } @@ -231,7 +231,7 @@ Debug.WriteLine(String.Format("{0,-50} {1,-30} affected={2,-5} total={3,-5}", Name, reason, affectedModules, counter), "UPDATED"); } } - + // TODO: optimize internal int Updated(ref int affectedModules) { _version = Interlocked.Increment(ref _globalVersion); @@ -280,11 +280,12 @@ _methods = (module._methods != null) ? new Dictionary(module._methods) : null; _classVariables = (module._classVariables != null) ? new Dictionary(module._classVariables) : null; - _mixins = ArrayUtils.Copy(module._mixins); + _mixins.Clear(); + AddMixins(module._mixins); // dependentModules - skip // tracker - skip, .NET members not copied - + Updated("InitializeFrom"); } @@ -307,8 +308,8 @@ public static RubyModule/*!*/ CreateAnonymousModule(CodeContext/*!*/ context, BlockParam block) { // TODO: throw new NotImplementedException(); - } - + } + public RubyClass/*!*/ CreateSingletonClass() { //^ ensures result.IsSingletonClass && !result.IsDummySingletonClass @@ -332,7 +333,7 @@ return ForEachDeclaredAncestor(action); } } - + protected virtual bool ForEachAncestor(Func/*!*/ action) { return ForEachDeclaredAncestor(action); } @@ -356,7 +357,7 @@ public SymbolId MakeNestedModuleName(SymbolId nestedModuleSimpleName) { return ReferenceEquals(this, _executionContext.ObjectClass) || nestedModuleSimpleName.IsEmpty ? - nestedModuleSimpleName : + nestedModuleSimpleName : SymbolTable.StringToId(_name + "::" + nestedModuleSimpleName); } @@ -364,7 +365,7 @@ ForEachAncestor(inherited, delegate(RubyModule/*!*/ module) { // notification that we entered the module (it could have no constant): if (action(module, SymbolId.Empty, Missing.Value)) return true; - + return module.EnumerateConstants(action); }); } @@ -376,7 +377,7 @@ EnsureInitialized(); _constants[name] = value; } - + // TODO: we don't do dynamic constant lookup, so there is no need to update the class // Updated("SetConstant"); } @@ -434,10 +435,10 @@ } EnsureInitialized(); - + if (_constants != null && _constants.TryGetValue(name, out value)) { return true; - } + } if (_clrConstants != null && _clrConstants.TryGetValue(name, out value)) { value = TrackerToModule(value); @@ -453,7 +454,7 @@ if (typeGroup != null) { return value; } - + // TypeTracker retrieved from namespace tracker should behave like a RubyClass/RubyModule: TypeTracker typeTracker = value as TypeTracker; if (typeTracker != null) { @@ -505,7 +506,7 @@ // skip interfaces (methods declared on interfaces have already been looked for in the class); // if 'this' is an interface, we want to visit all interface methods: if (module.IsInterface && !this.IsInterface) return false; - + // notification that we entered the module (it could have no method): if (action(module, SymbolId.Empty, null)) return true; @@ -530,24 +531,24 @@ // Update only if the current method overrides/redefines another one higher in the inheritance hierarchy. // Method lookup failures are not cached in dynamic sites. // Therefore a future invocation of the method will trigger resolution in binder that will find just added method. - // If, on the other hand, a method is overriden there might be a dynamic site that caches a method call to that method. + // If, on the other hand, a method is overridden there might be a dynamic site that caches a method call to that method. // In that case we need to update version to invalidate the site. - - RubyMemberInfo overridenMethod = ResolveMethodUsedInDynamicSite(name); - + + RubyMemberInfo overriddenMethod = ResolveMethodUsedInDynamicSite(name); + // TODO: cache this? (definition of method_missing could updated all subclasses): - if (overridenMethod == null) { - overridenMethod = ResolveMethodUsedInDynamicSite(Symbols.MethodMissing); + if (overriddenMethod == null) { + overriddenMethod = ResolveMethodUsedInDynamicSite(Symbols.MethodMissing); // TODO: better check for builtin method - if (overridenMethod != null && overridenMethod.DeclaringModule == ExecutionContext.KernelModule && overridenMethod is RubyMethodGroupInfo) { - overridenMethod = null; + if (overriddenMethod != null && overriddenMethod.DeclaringModule == ExecutionContext.KernelModule && overriddenMethod is RubyMethodGroupInfo) { + overriddenMethod = null; } } EnsureInitialized(); _methods[name] = method; - if (overridenMethod != null) { + if (overriddenMethod != null) { // TODO: stop updating if a module that defines a method of the same name is reached: Updated("SetMethod: " + name); } @@ -584,7 +585,7 @@ _methods[name] = RubyMethodInfo.HiddenMethod; Updated("HideMethod"); } - + public void HideMethod(string/*!*/ name) { HideMethod(SymbolTable.StringToId(name)); } @@ -786,7 +787,7 @@ } internal void SetMixins(IList/*!*/ modules) { - Debug.Assert(_mixins.Length == 0); + Debug.Assert(_mixins.Count == 0); Debug.Assert(modules != null && CollectionUtils.TrueForAll(modules, delegate(RubyModule m) { return m != null && !m.IsClass; })); List allModules = new List(); @@ -794,7 +795,8 @@ SetDependency(modules); // do not initialize modules: - _mixins = allModules.ToArray(); + _mixins.Clear(); + AddMixins(allModules); Updated("SetMixins"); } @@ -804,11 +806,32 @@ // transitively include modules: List allModules = new List(); - for (int i = 0; i < modules.Length; i++) { - allModules.Add(modules[i]); - GetMixinsRecursive(allModules, modules[i]._mixins); + foreach (RubyModule module in modules) { + allModules.Add(module); + GetMixinsRecursive(allModules, module._mixins); } + foreach (RubyModule module in allModules) { + if (module.IsInterface) { + // Can't include generic interfaces + if (module.Tracker.Type.ContainsGenericParameters) { + throw RubyExceptions.CreateTypeError(String.Format( + "{0}: cannot extend with open generic instantiation {1}. Only closed instantiations are supported.", + Name, module.Name + )); + } + + if (!CanIncludeClrInterface) { + if (CollectionUtils.TrueForAll(_mixins, delegate(RubyModule m) { return m != module; })) { + throw new InvalidOperationException(String.Format( + "Interface {0} cannot be included in class {1} because its underlying type has already been created.", + module.Name, Name + )); + } + } + } + } + SetDependency(allModules); // initialize added modules: @@ -818,19 +841,46 @@ } } - // new modules are inserted at the beginning so they come first in MRO - _mixins = ArrayUtils.InsertAt(_mixins, 0, allModules.ToArray()); + AddMixins(allModules); Updated("IncludeModules"); } - internal static void GetMixinsRecursive(List/*!*/ result, IList/*!*/ modules) { - for (int i = 0; i < modules.Count; i++) { - result.Add(modules[i]); - GetMixinsRecursive(result, modules[i]._mixins); + private void AddMixins(IList allModules) { + // new modules are inserted at the beginning so they come first in MRO + if (_mixins.Capacity < _mixins.Count + allModules.Count) { + _mixins.Capacity = _mixins.Count + allModules.Count; } + int position = 0; + foreach (RubyModule module in allModules) { + if (!_mixins.Contains(module)) { + _mixins.Insert(position++, module); + } + } } + internal static void GetMixinsRecursive(List/*!*/ result, IList/*!*/ modules) { + foreach (RubyModule module in modules) { + result.Add(module); + GetMixinsRecursive(result, module._mixins); + } + } + + + protected virtual bool CanIncludeClrInterface { + get { return true; } + } + + protected List GetClrInterfaces() { + List interfaces = new List(); + foreach (RubyModule m in _mixins) { + if (m.IsInterface && !interfaces.Contains(m.Tracker.Type)) { + interfaces.Add(m.Tracker.Type); + } + } + return interfaces; + } + internal void IncludeTrait(Action/*!*/ trait) { Assert.NotNull(trait); @@ -848,7 +898,7 @@ internal void IncludeLibraryModule(Action instanceTrait, Action classTrait, RubyModule[]/*!*/ mixins) { Assert.NotNull(mixins); - + IncludeModules(mixins); if (instanceTrait != null) { @@ -865,7 +915,7 @@ internal void AddFullVersionTest(MetaObjectBuilder/*!*/ metaBuilder, MSA.Expression/*!*/ codeContextExpression) { Assert.NotNull(metaBuilder); EnsureInitialized(); // Initialization changes the version number, so ensure that the module is initialized - + // TODO: runtime check could be a restriction metaBuilder.AddCondition(AstFactory.OpCall("CheckVersionAndRuntime", codeContextExpression, =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Generation/RubyTypeBuilder.cs;C520315 File: RubyTypeBuilder.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Generation/RubyTypeBuilder.cs;C520315 (server) 8/4/2008 2:20 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Generation/RubyTypeBuilder.cs;rubyclrinterop01 @@ -19,7 +19,9 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; +using System.Text; using System.Threading; +using Microsoft.Scripting; using Microsoft.Scripting.Generation; using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; @@ -28,61 +30,67 @@ namespace Ruby.Compiler.Generation { internal sealed class RubyTypeBuilder { - // base type that doesn't implement IRubyObject -> Ruby subtype that does - private static readonly Dictionary/*!*/ _RubyTypes; // synchronized + private static readonly Publisher _newTypes; static RubyTypeBuilder() { - _RubyTypes = new Dictionary(); - _RubyTypes.Add(typeof(object), typeof(RubyObject)); - _RubyTypes.Add(typeof(MutableString), typeof(MutableString.Subclass)); - _RubyTypes.Add(typeof(Proc), typeof(Proc.Subclass)); + _newTypes = new Publisher(); + + _newTypes.GetOrCreateValue(new TypeDescription(typeof(object)), delegate() { return typeof(RubyObject); }); + _newTypes.GetOrCreateValue(new TypeDescription(typeof(MutableString)), delegate() { return typeof(MutableString.Subclass); }); + _newTypes.GetOrCreateValue(new TypeDescription(typeof(Proc)), delegate() { return typeof(Proc.Subclass); }); } + [MultiRuntimeAware] private static int _typeCounter; - internal static Type/*!*/ GetOrCreateType(Type/*!*/ baseType) { + private readonly Type/*!*/ _baseType; + private readonly IEnumerable/*!*/ _interfaceTypes; + private TypeBuilder _tb; + private FieldBuilder _classField; + private FieldBuilder _instanceDataField; + + internal static Type/*!*/ GetOrCreateType(Type/*!*/ baseType, IList/*!*/ interfaces) { Assert.NotNull(baseType); + Assert.NotNull(interfaces); - Type type; - if (typeof(IRubyObject).IsAssignableFrom(baseType)) { - type = baseType; - } else { - lock (_RubyTypes) { - if (!_RubyTypes.TryGetValue(baseType, out type)) { - type = CreateType(baseType); - _RubyTypes.Add(baseType, type); - } - } - } + TypeDescription typeInfo = new TypeDescription(baseType, interfaces); + Type type = _newTypes.GetOrCreateValue(typeInfo, + delegate() { + return new RubyTypeBuilder(typeInfo).CreateType(); + }); Debug.Assert(typeof(IRubyObject).IsAssignableFrom(type)); return type; } - private static Type/*!*/ CreateType(Type/*!*/ baseType) { - if (baseType.IsSealed) { + internal RubyTypeBuilder(TypeDescription /*!*/ typeInfo) { + _baseType = typeInfo.BaseType; + _interfaceTypes = typeInfo.InterfaceTypes; + } + + private Type/*!*/ CreateType() { + if (_baseType.IsSealed) { throw new NotSupportedException("Can't inherit from a sealed type."); } // make sure to generate a call to the base class constructor: - int counter = Interlocked.Increment(ref _typeCounter); - string typeName = "Ruby.Classes." + baseType.Name + counter; - TypeBuilder tb = Snippets.Shared.DefinePublicType(typeName, baseType); + string typeName = GetName(); + _tb = Snippets.Shared.DefinePublicType(typeName, _baseType); Debug.WriteLine(typeName, "TYPE BUILDER"); // fields: - FieldBuilder classField = tb.DefineField("_class", typeof(RubyClass), FieldAttributes.Private | FieldAttributes.InitOnly); - FieldBuilder instanceDataField = tb.DefineField("_instanceData", typeof(RubyInstanceData), FieldAttributes.Private); + _classField = _tb.DefineField("_class", typeof(RubyClass), FieldAttributes.Private | FieldAttributes.InitOnly); + _instanceDataField = _tb.DefineField("_instanceData", typeof(RubyInstanceData), FieldAttributes.Private); - DefineConstructors(tb, instanceDataField, classField); - DefineRubyObjectImplementation(tb, instanceDataField, classField); - DefineSerializer(tb, instanceDataField, classField); + DefineConstructors(); + DefineRubyObjectImplementation(); + DefineSerializer(); // TODO: use MetaObjects - // DefineDynamicObjectImplementation(tb); + // DefineDynamicObjectImplementation(); + ImplementInterfaces(); - // we need to get the right execution context #if OBSOLETE // TODO: remove the need for these methods to be special cased @@ -90,8 +98,18 @@ EmitOverrideGetHashCode(typeGen); #endif + return _tb.CreateType(); + } - return tb.CreateType(); + private string GetName() { + StringBuilder name = new StringBuilder("Ruby.Classes."); + name.Append(_baseType.Name); + name.Append(Interlocked.Increment(ref _typeCounter)); + foreach (Type interfaceType in _interfaceTypes) { + name.Append("#"); + name.Append(interfaceType.Name); + } + return name.ToString(); } #if !SILVERLIGHT @@ -101,32 +119,32 @@ return method != null && !method.IsPrivate && !method.IsFamilyAndAssembly; } - private static void DefineConstructors(TypeBuilder/*!*/ tb, FieldInfo/*!*/ instanceDataField, FieldInfo/*!*/ classField) { + private void DefineConstructors() { BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; // ctor(RubyClass! class) : ... { this._class = class; } - ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, + ConstructorBuilder ctor = _tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(RubyClass) } ); ILGen il = new ILGen(ctor.GetILGenerator()); ConstructorInfo baseCtor; - if (IsAvailable(baseCtor = tb.BaseType.GetConstructor(bindingFlags, null, new Type[] { typeof(RubyClass) }, null))) { + if (IsAvailable(baseCtor = _tb.BaseType.GetConstructor(bindingFlags, null, new Type[] { typeof(RubyClass) }, null))) { // : base(class) il.EmitLoadArg(0); il.EmitLoadArg(1); il.Emit(OpCodes.Call, baseCtor); - } else if (IsAvailable(baseCtor = tb.BaseType.GetConstructor(bindingFlags, null, Type.EmptyTypes, null))) { + } else if (IsAvailable(baseCtor = _tb.BaseType.GetConstructor(bindingFlags, null, Type.EmptyTypes, null))) { // : base() il.EmitLoadArg(0); il.Emit(OpCodes.Call, baseCtor); } else { - throw new NotSupportedException("No compatible constructor found for class " + tb.BaseType.FullName); + throw new NotSupportedException("No compatible constructor found for class " + _tb.BaseType.FullName); } - + il.EmitLoadArg(0); il.EmitLoadArg(1); - il.EmitFieldSet(classField); + il.EmitFieldSet(_classField); il.Emit(OpCodes.Ret); #if !SILVERLIGHT @@ -134,10 +152,10 @@ // RubyOps.DeserializeObject(out this._instanceData, out this._class, info); // } - ConstructorBuilder deserializer = tb.DefineConstructor(MethodAttributes.Family, CallingConventions.Standard, _deserializerSignature); + ConstructorBuilder deserializer = _tb.DefineConstructor(MethodAttributes.Family, CallingConventions.Standard, _deserializerSignature); il = new ILGen(deserializer.GetILGenerator()); - ConstructorInfo baseDeserializer = tb.BaseType.GetConstructor(bindingFlags, null, _deserializerSignature, null); + ConstructorInfo baseDeserializer = _tb.BaseType.GetConstructor(bindingFlags, null, _deserializerSignature, null); if (IsAvailable(baseDeserializer)) { // : base(info, context) { @@ -155,44 +173,44 @@ } il.EmitLoadArg(0); - il.EmitFieldAddress(instanceDataField); + il.EmitFieldAddress(_instanceDataField); il.EmitLoadArg(0); - il.EmitFieldAddress(classField); + il.EmitFieldAddress(_classField); il.EmitLoadArg(1); il.EmitCall(typeof(RubyOps).GetMethod("DeserializeObject")); il.Emit(OpCodes.Ret); #endif } - private static void DefineRubyObjectImplementation(TypeBuilder/*!*/ tb, FieldInfo/*!*/ instanceDataField, FieldInfo/*!*/ classField) { - tb.AddInterfaceImplementation(typeof(IRubyObject)); + private void DefineRubyObjectImplementation() { + _tb.AddInterfaceImplementation(typeof(IRubyObject)); ILGen il; // RubyClass! IRubyObject.RubyClass { get { return this._class; } } - il = DefineMethodOverride(tb, typeof(IRubyObject).GetProperty(RubyObject.ClassPropertyName).GetGetMethod()); + il = DefineMethodOverride(_tb, typeof(IRubyObject).GetProperty(RubyObject.ClassPropertyName).GetGetMethod()); il.EmitLoadArg(0); - il.EmitFieldGet(classField); + il.EmitFieldGet(_classField); il.Emit(OpCodes.Ret); // RubyInstanceData IRubyObject.TryGetInstanceData() { return this._instanceData; } - il = DefineMethodOverride(tb, typeof(IRubyObject).GetMethod("TryGetInstanceData")); + il = DefineMethodOverride(_tb, typeof(IRubyObject).GetMethod("TryGetInstanceData")); il.EmitLoadArg(0); - il.EmitFieldGet(instanceDataField); + il.EmitFieldGet(_instanceDataField); il.Emit(OpCodes.Ret); // RubyInstanceData! IRubyObject.GetInstanceData() { return RubyOps.GetInstanceData(ref _instanceData); } - il = DefineMethodOverride(tb, typeof(IRubyObject).GetMethod("GetInstanceData")); + il = DefineMethodOverride(_tb, typeof(IRubyObject).GetMethod("GetInstanceData")); il.EmitLoadArg(0); - il.EmitFieldAddress(instanceDataField); + il.EmitFieldAddress(_instanceDataField); il.EmitCall(typeof(RubyOps).GetMethod("GetInstanceData")); il.Emit(OpCodes.Ret); } - private static void DefineSerializer(TypeBuilder/*!*/ tb, FieldBuilder/*!*/ instanceDataField, FieldBuilder/*!*/ classField) { + private void DefineSerializer() { #if !SILVERLIGHT ILGen il; - tb.AddInterfaceImplementation(typeof(ISerializable)); + _tb.AddInterfaceImplementation(typeof(ISerializable)); // void ISerializable.GetObjectData(SerializationInfo! info, StreamingContext! context) { // base.GetObjectData(info, context); @@ -200,14 +218,14 @@ // } MethodInfo baseSerializer; - if (typeof(ISerializable).IsAssignableFrom(tb.BaseType)) { - InterfaceMapping map = tb.BaseType.GetInterfaceMap(typeof(ISerializable)); + if (typeof(ISerializable).IsAssignableFrom(_tb.BaseType)) { + InterfaceMapping map = _tb.BaseType.GetInterfaceMap(typeof(ISerializable)); baseSerializer = map.TargetMethods[0]; } else { baseSerializer = null; } - - il = DefineMethodOverride(tb, typeof(ISerializable).GetMethod("GetObjectData")); + + il = DefineMethodOverride(_tb, typeof(ISerializable).GetMethod("GetObjectData")); if (baseSerializer != null) { il.EmitLoadArg(0); il.EmitLoadArg(1); @@ -216,9 +234,9 @@ } il.EmitLoadArg(0); - il.EmitFieldGet(instanceDataField); + il.EmitFieldGet(_instanceDataField); il.EmitLoadArg(0); - il.EmitFieldGet(classField); + il.EmitFieldGet(_classField); il.EmitLoadArg(1); il.EmitCall(typeof(RubyOps).GetMethod("SerializeObject")); il.Emit(OpCodes.Ret); @@ -280,16 +298,17 @@ cg.Finish(); } +#endif - private static void DefineDynamicObjectImplementation(TypeBuilder/*!*/ tb) { - tb.AddInterfaceImplementation(typeof(IOldDynamicObject)); + private void DefineDynamicObjectImplementation() { + _tb.AddInterfaceImplementation(typeof(IOldDynamicObject)); // MetaObjectBuilder! IOldDynamicObject.GetRule(OldDynamicAction! action, CodeContext! context, object[]! args) where T : class { // return RubyOps.GetClassRule(action, context, args); // } MethodInfo decl = typeof(IOldDynamicObject).GetMethod("GetRule"); - MethodBuilder impl = tb.DefineMethod( + MethodBuilder impl = _tb.DefineMethod( decl.Name, decl.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.ReservedMask), decl.ReturnType, @@ -299,7 +318,7 @@ types[0].SetGenericParameterAttributes(GenericParameterAttributes.ReferenceTypeConstraint); ILGen il = new ILGen(impl.GetILGenerator()); - + MethodInfo mi = typeof(RubyOps).GetMethod("GetClassRule").MakeGenericMethod(types); il.EmitLoadArg(1); il.EmitLoadArg(2); @@ -307,9 +326,8 @@ il.EmitCall(mi); il.Emit(OpCodes.Ret); - tb.DefineMethodOverride(impl, decl); + _tb.DefineMethodOverride(impl, decl); } -#endif private static ILGen/*!*/ DefineMethodOverride(TypeBuilder/*!*/ tb, MethodInfo/*!*/ decl) { MethodBuilder impl; @@ -327,5 +345,16 @@ tb.DefineMethodOverride(impl, decl); return new ILGen(impl.GetILGenerator()); } + + private void ImplementInterfaces() { + foreach (Type interfaceType in _interfaceTypes) { + ImplementInterface(interfaceType); + } + } + + private void ImplementInterface(Type interfaceType) { + // TODO: Implement + // _tb.AddInterfaceImplementation(interfaceType); + } } } =================================================================== add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Generation/TypeDescription.cs File: TypeDescription.cs =================================================================== --- [no source file] +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Generation/TypeDescription.cs;rubyclrinterop01 @@ -1,0 +1,106 @@ +?/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Microsoft Public License. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Microsoft Public License, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Microsoft Public License. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using Microsoft.Scripting.Utils; + +namespace Ruby.Compiler.Generation { + + /// + /// TypeDescription captures the minimal information required by TypeBuilder to define a distinct CLS type + /// + internal class TypeDescription { + // The CLI base-type. + private readonly Type/*!*/ _baseType; + + private readonly List/*!*/ _interfaceTypes; + protected Nullable _hash; + + public TypeDescription(Type/*!*/ baseType) + : this(baseType, Type.EmptyTypes) { + } + + public TypeDescription(Type/*!*/ baseType, IList/*!*/ interfaceTypes) { + _baseType = baseType; + _interfaceTypes = new List(interfaceTypes.Count); + foreach (Type t in interfaceTypes) { + AddInterface(t); + } + SortInterfaces(); + } + + public Type/*!*/ BaseType { + get { return _baseType; } + } + + public IList/*!*/ InterfaceTypes { + get { return _interfaceTypes; } + } + + protected void AddInterface(Type/*!*/ type) { + Assert.NotNull(type); + Assert.Equals(true, type.IsInterface && !type.ContainsGenericParameters); + + for (int i = 0; i < _interfaceTypes.Count; i++) { + Type t = _interfaceTypes[i]; + if (t == type || type.IsAssignableFrom(t)) { + // This interface is already included in the list + return; + } + if (t.IsAssignableFrom(type)) { + // We are going to supercede this interface + _interfaceTypes.RemoveAt(i--); + } + } + _interfaceTypes.Add(type); + _hash = null; + } + + protected void SortInterfaces() { + _interfaceTypes.Sort(delegate(Type a, Type b) { return a.FullName.CompareTo(b.FullName); }); + } + + public override int GetHashCode() { + if (_hash == null) { + int hashCode = _baseType.GetHashCode(); + for (int i = 0; i < _interfaceTypes.Count; i++) { + hashCode ^= _interfaceTypes[i].GetHashCode(); + } + _hash = hashCode; + } + + return _hash.Value; + } + + public override bool Equals(object obj) { + TypeDescription other = obj as TypeDescription; + if (other == null) return false; + + if (_baseType.Equals(other._baseType) && + _interfaceTypes.Count == other._interfaceTypes.Count) { + + for (int i = 0; i < _interfaceTypes.Count; i++) { + if (!_interfaceTypes[i].Equals(other._interfaceTypes[i])) { + return false; + } + } + + return true; + } + return false; + } + } +} =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExecutionContext.cs;C518603 File: RubyExecutionContext.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExecutionContext.cs;C518603 (server) 8/6/2008 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyExecutionContext.cs;rubyclrinterop01 @@ -57,7 +57,7 @@ /// $KCODE /// private static KCode _kcode; - + /// /// $/, $-O /// @@ -183,7 +183,7 @@ ); } - site.Target(site, context, obj, methodName); + site.Target(site, context, obj, methodName); } private void ClassInheritedEvent(RubyClass/*!*/ superClass, RubyClass/*!*/ subClass) { @@ -201,8 +201,8 @@ #endregion public Exception CurrentException { - get { return _currentException; } - set { _currentException = value; } + get { return _currentException; } + set { _currentException = value; } } public int CurrentSafeLevel { @@ -235,7 +235,7 @@ public Proc TraceListener { get { return _traceListener; } - set { _traceListener = value; } + set { _traceListener = value; } } public IEnumerable>/*!*/ GlobalVariables { @@ -255,8 +255,8 @@ } public object ChildProcessExitStatus { - get { return _childProcessExitStatus; } - set { _childProcessExitStatus = value; } + get { return _childProcessExitStatus; } + set { _childProcessExitStatus = value; } } public Scope/*!*/ TopGlobalScope { @@ -321,7 +321,7 @@ _stringSeparator = null; _itemSeparator = null; _kcode = KCode.Default; - + _loader = new Loader(this, context.RubyOptions.SearchPaths); if (!_loader.TryLoadBuiltins()) { @@ -361,12 +361,12 @@ // $? - + // $0 if (_context.RubyOptions.MainFile != null) { DefineGlobalVariableNoLock(Symbols.CommandLineProgramPath, new GlobalVariableInfo(MutableString.Create(_context.RubyOptions.MainFile))); } - + DefineGlobalVariableNoLock(SymbolTable.StringToId("stdin"), new GlobalVariableInfo(StandardInput)); DefineGlobalVariableNoLock(SymbolTable.StringToId("stdout"), Runtime.GlobalVariables.OutputStream); DefineGlobalVariableNoLock(SymbolTable.StringToId("stderr"), new GlobalVariableInfo(StandardErrorOutput)); @@ -427,7 +427,7 @@ _objectClass.SetConstant("RELEASE_DATE", releaseDate); _objectClass.SetConstant("IRONRUBY_VERSION", MutableString.Create(RubyContext.IronRubyVersionString)); - + _objectClass.SetConstant("STDIN", StandardInput); _objectClass.SetConstant("STDOUT", StandardOutput); _objectClass.SetConstant("STDERR", StandardErrorOutput); @@ -463,10 +463,10 @@ Action/*!*/ mainSingletonTrait, Action/*!*/ kernelInstanceTrait, - Action/*!*/ objectInstanceTrait, - Action/*!*/ moduleInstanceTrait, + Action/*!*/ objectInstanceTrait, + Action/*!*/ moduleInstanceTrait, Action/*!*/ classInstanceTrait, - + Action/*!*/ kernelClassTrait, Action/*!*/ objectClassTrait, Action/*!*/ moduleClassTrait, @@ -498,9 +498,9 @@ // we need to create object class before any other since constants are added in its dictionary: _kernelModule = new RubyModule(this, Symbols.Kernel, kernelInstanceTrait, null, null); - _objectClass = new RubyClass(this, Symbols.Object, objectTracker.Type, null, objectInstanceTrait, null, objectTracker, false); - _moduleClass = new RubyClass(this, Symbols.Module, typeof(RubyModule), null, moduleInstanceTrait, _objectClass, null, false); - _classClass = new RubyClass(this, Symbols.Class, typeof(RubyClass), null, classInstanceTrait, _moduleClass, null, false); + _objectClass = new RubyClass(this, Symbols.Object, objectTracker.Type, null, objectInstanceTrait, null, objectTracker, false, false); + _moduleClass = new RubyClass(this, Symbols.Module, typeof(RubyModule), null, moduleInstanceTrait, _objectClass, null, false, false); + _classClass = new RubyClass(this, Symbols.Class, typeof(RubyClass), null, classInstanceTrait, _moduleClass, null, false, false); CreateDummySingletonClassFor(_kernelModule, _moduleClass, kernelClassTrait); CreateDummySingletonClassFor(_objectClass, _classClass, objectClassTrait); @@ -544,12 +544,12 @@ internal RubyModule/*!*/ GetOrCreateModule(NamespaceTracker/*!*/ tracker) { Assert.NotNull(tracker); - + lock (ModuleCacheSyncRoot) { return GetOrCreateModuleNoLock(tracker); } } - + internal bool TryGetModule(NamespaceTracker/*!*/ namespaceTracker, out RubyModule result) { lock (NamespaceCacheSyncRoot) { return _namespaceCache.TryGetValue(namespaceTracker, out result); @@ -581,7 +581,7 @@ return false; } } - + internal RubyClass/*!*/ GetOrCreateClass(Type/*!*/ type) { Debug.Assert(type != null && !type.IsInterface); @@ -589,10 +589,10 @@ return GetOrCreateClassNoLock(type); } } - + private RubyModule/*!*/ GetOrCreateModuleNoLock(NamespaceTracker/*!*/ tracker) { Assert.NotNull(tracker); - + RubyModule result; if (_namespaceCache.TryGetValue(tracker, out result)) { return result; @@ -616,7 +616,7 @@ _moduleCache[interfaceType] = result; return result; } - + private RubyClass/*!*/ GetOrCreateClassNoLock(Type/*!*/ type) { Debug.Assert(type != null && !type.IsInterface); @@ -628,7 +628,7 @@ RubyClass baseClass = GetOrCreateClassNoLock(type.BaseType); TypeTracker tracker = (TypeTracker)TypeTracker.FromMemberInfo(type); - result = CreateClass(SymbolTable.StringToId(RubyUtils.GetQualifiedName(type)), type, null, null, null, baseClass, tracker, false); + result = CreateClass(SymbolTable.StringToId(RubyUtils.GetQualifiedName(type)), type, null, null, null, baseClass, tracker, false, false); List interfaceMixins = GetDeclaredInterfaceModules(type); if (interfaceMixins != null) { @@ -657,17 +657,16 @@ #region Class and Module Factories - internal RubyClass/*!*/ CreateClass(SymbolId name, Type type, object classSingletonOf, Action instanceTrait, Action classTrait, - RubyClass/*!*/ superClass, TypeTracker tracker, bool isRubyClass) { + internal RubyClass/*!*/ CreateClass(SymbolId name, Type type, object classSingletonOf, Action instanceTrait, Action classTrait, RubyClass/*!*/ superClass, TypeTracker tracker, bool isRubyClass, bool isSingletonClass) { Debug.Assert(superClass != null); - RubyClass result = new RubyClass(this, name, type, classSingletonOf, instanceTrait, superClass, tracker, isRubyClass); + RubyClass result = new RubyClass(this, name, type, classSingletonOf, instanceTrait, superClass, tracker, isRubyClass, isSingletonClass); CreateDummySingletonClassFor(result, superClass.SingletonClass, classTrait); return result; } - internal RubyModule/*!*/ CreateModule(SymbolId name, Action instanceTrait, Action classTrait, + internal RubyModule/*!*/ CreateModule(SymbolId name, Action instanceTrait, Action classTrait, NamespaceTracker namespaceTracker, TypeTracker typeTracker) { RubyModule result = new RubyModule(this, name, instanceTrait, namespaceTracker, typeTracker); CreateDummySingletonClassFor(result, _moduleClass, classTrait); @@ -678,10 +677,10 @@ // Note that in MRI, member tables of dummy singleton are shared with the class the dummy is singleton for // This is obviously an implementation detail leaking to the language and we don't support that for code clarity. - // real class object and it's singleton share tyhe tracker: + // real class object and it's singleton share the tracker: TypeTracker tracker = (module.IsSingletonClass) ? null : module.Tracker; - RubyClass result = new RubyClass(this, SymbolId.Empty, null, module, trait, superClass, tracker, false); + RubyClass result = new RubyClass(this, SymbolId.Empty, null, module, trait, superClass, tracker, false, true); result.SingletonClass = result; module.SingletonClass = result; #if DEBUG @@ -736,7 +735,7 @@ RubyClass c = GetClassOf(obj, data); - result = CreateClass(SymbolId.Empty, null, obj, instanceTrait, classTrait ?? _classSingletonTrait, c, null, true); + result = CreateClass(SymbolId.Empty, null, obj, instanceTrait, classTrait ?? _classSingletonTrait, c, null, true, true); c.Updated("CreateInstanceSingleton"); SetInstanceSingletonOf(obj, ref data, result); #if DEBUG @@ -763,9 +762,15 @@ ContractUtils.RequiresNotNull(owner, "owner"); ContractUtils.RequiresNotNull(superClass, "superClass"); + if (superClass.Tracker != null && superClass.Tracker.Type.ContainsGenericParameters) { + throw RubyExceptions.CreateTypeError(String.Format( + "{0}: cannot inherit from open generic instantiation {1}. Only closed instantiations are supported.", + SymbolTable.IdToString(name), superClass.Name + )); + } + SymbolId qualifiedName = owner.MakeNestedModuleName(name); - Type type = RubyTypeBuilder.GetOrCreateType(superClass.GetUnderlyingSystemType()); - RubyClass result = CreateClass(qualifiedName, type, null, null, null, superClass, null, true); + RubyClass result = CreateClass(qualifiedName, null, null, null, null, superClass, null, true, false); if (!name.IsEmpty) { owner.SetConstant(name, result); @@ -791,8 +796,8 @@ if (TryGetModuleNoLock(type, out module)) { module.IncludeLibraryModule(instanceTrait, classTrait, mixins); return module; - } - + } + if (name == null) { name = RubyUtils.GetQualifiedName(type); } @@ -827,8 +832,8 @@ } return result; - } - + } + if (name == null) { name = RubyUtils.GetQualifiedName(type); } @@ -840,7 +845,7 @@ // setting tracker on the class makes CLR methods visible: TypeTracker tracker = ReflectionCache.GetTypeTracker(type); - result = CreateClass(SymbolTable.StringToId(name), type, null, instanceTrait, classTrait, super, tracker, false); + result = CreateClass(SymbolTable.StringToId(name), type, null, instanceTrait, classTrait, super, tracker, false, false); result.SetMixins(mixins); result.Factories = factories; @@ -874,11 +879,11 @@ ContractUtils.Requires(!type.IsInterface); return GetOrCreateClass(type); } - + /// /// Gets a class of the specified object (skips any singletons). /// - public RubyClass/*!*/ GetClassOf(object obj) + public RubyClass/*!*/ GetClassOf(object obj) //^ ensures !result.IsSingletonClass; { if (obj == null) { @@ -905,7 +910,7 @@ if (module != null) { return module.SingletonClass; } - + RubyInstanceData data; RubyClass result = TryGetInstanceSingletonOf(obj, out data); if (result != null) { @@ -929,7 +934,7 @@ private void SetInstanceSingletonOf(object obj, ref RubyInstanceData data, RubyClass/*!*/ singleton) { Debug.Assert(!(obj is RubyModule) && singleton != null); - + if (data == null) { data = GetInstanceData(obj); } @@ -1125,7 +1130,7 @@ TryGetGlobalVariable(null, SymbolTable.StringToId(name), out value); return value; } - + public void DefineGlobalVariable(SymbolId name, object value) { lock (_globalVariables) { _globalVariables[name] = new GlobalVariableInfo(value); @@ -1247,7 +1252,7 @@ public void SetKCode(MutableString encodingName) { // TODO: Ruby 1.9 reports a warning: - + // we allow nil as Ruby 1.9 does: if (encodingName == null) { _kcode = KCode.Default; @@ -1269,7 +1274,7 @@ case 'u': _kcode = KCode.Utf8; break; - + default: _kcode = KCode.Binary; break; @@ -1353,10 +1358,10 @@ internal void MethodAdded(RubyModule/*!*/ module, SymbolId name) { // not called on singleton classes: if (!module.IsSingletonClass) { - MethodEvent(ref _methodAddedCallbackSite, Symbols.MethodAdded, + MethodEvent(ref _methodAddedCallbackSite, Symbols.MethodAdded, _context.EmptyContext, module, name); } else { - SingletonMethodEvent(ref _singletonMethodAddedCallbackSite, Symbols.SingletonMethodAdded, + SingletonMethodEvent(ref _singletonMethodAddedCallbackSite, Symbols.SingletonMethodAdded, _context.EmptyContext, ((RubyClass)module).SingletonClassOf, name); } } @@ -1364,7 +1369,7 @@ internal void MethodRemoved(RubyModule/*!*/ module, SymbolId name) { // not called on singleton classes: if (!module.IsSingletonClass) { - MethodEvent(ref _methodRemovedCallbackSite, Symbols.MethodRemoved, + MethodEvent(ref _methodRemovedCallbackSite, Symbols.MethodRemoved, _context.EmptyContext, module, name); } else { SingletonMethodEvent(ref _singletonMethodRemovedCallbackSite, Symbols.SingletonMethodRemoved, @@ -1375,7 +1380,7 @@ internal void MethodUndefined(RubyModule/*!*/ module, SymbolId name) { // not called on singleton classes: if (!module.IsSingletonClass) { - MethodEvent(ref _methodUndefinedCallbackSite, Symbols.MethodUndefined, + MethodEvent(ref _methodUndefinedCallbackSite, Symbols.MethodUndefined, _context.EmptyContext, module, name); } else { SingletonMethodEvent(ref _singletonMethodUndefinedCallbackSite, Symbols.SingletonMethodUndefined, @@ -1386,10 +1391,10 @@ internal void MethodCalled(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) { if (_traceListener != null && !_traceListenerSuspended) { if (!_traceListenerCallbackSite.IsInitialized) { - _traceListenerCallbackSite.EnsureInitialized(OldCallAction.Make(scope.LanguageContext.Binder, + _traceListenerCallbackSite.EnsureInitialized(OldCallAction.Make(scope.LanguageContext.Binder, new CallSignature(ArgumentKind.List))); } - + try { _traceListenerSuspended = true; =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs;C520315 File: ProtocolConversionAction.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs;C520315 (server) 8/13/2008 8:52 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs;rubyclrinterop01 @@ -90,7 +90,7 @@ SymbolId toMethodName = ToMethodName; string targetClassName = SymbolTable.IdToString(ec.GetClassOf(args.Target).Name); - // Kernel#respond_to? method is not overriden => we could optimize + // Kernel#respond_to? method is not overridden => we could optimize RubyMemberInfo respondToMethod = ec.ResolveMethodForSite(args.Target, Symbols.RespondTo); if (respondToMethod == null || // the method is defined in library, hasn't been replaced by user defined method (TODO: maybe we should make this check better) =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Interop/test_basic.rb;C503216 File: test_basic.rb =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Interop/test_basic.rb;C503216 (server) 8/8/2008 12:14 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Tests/Interop/test_basic.rb;rubyclrinterop01 @@ -228,6 +228,36 @@ assert_equal(type.is_assignable_from(type), true) end +def test_generics_give_type_error + assert_raise(TypeError) do + Class.new(System::Collections::Generic::List) + end + assert_raise(TypeError) do + Class.new do + include System::Collections::Generic::List + end + end +end + +def test_include_interface_after_type_creation + c = Class.new do + include System::Collections::Generic::List[System::Int32] + end + + # No object has been instantiated so we should be able to reopen the class and add a new interface + c.class_eval do + include System::IDisposable + end + + # After instantiating the object, this will give us an error + tmp = c.new + assert_raise(TypeError) do + c.class_eval do + include System::IDisposable + end + end +end + test_event test_field test_string ===================================================================