Index: tests/testcases/net2/generics/generic-ref-parameter.boo =================================================================== --- tests/testcases/net2/generics/generic-ref-parameter.boo (revision 0) +++ tests/testcases/net2/generics/generic-ref-parameter.boo (revision 0) @@ -0,0 +1,13 @@ +import System.Collections.Generic + +class Foo: + pass + +d = Dictionary[of string, Foo]() +f1 = Foo() +d["Key"] = f1 + +f2 as Foo +d.TryGetValue("Key", f2) + +assert f1 is f2 Index: tests/testcases/net2/generics/generic-method-invocation-1.boo =================================================================== --- tests/testcases/net2/generics/generic-method-invocation-1.boo (revision 0) +++ tests/testcases/net2/generics/generic-method-invocation-1.boo (revision 0) @@ -0,0 +1,12 @@ +""" +01 +02 +03 +04 +""" + +import System + +ints = (1,2,3,4) +strings = Array.ConvertAll[of int, string](ints, {i as int | i.ToString("00")}) +for s in strings: print s Index: tests/testcases/net2/generics/generic-method-invocation-2.boo =================================================================== --- tests/testcases/net2/generics/generic-method-invocation-2.boo (revision 0) +++ tests/testcases/net2/generics/generic-method-invocation-2.boo (revision 0) @@ -0,0 +1,21 @@ +""" +Foo #1 +Foo #2 +Foo #3 +Foo #4 +""" + +import System + +class Foo: + public _i as int + + public def constructor(i as int): + _i = i + + public def ToString(): + return "Foo #${_i}"; + +ints = (1,2,3,4) +strings = Array.ConvertAll[of int, Foo](ints, {i as int | Foo(i)}) +for s in strings: print s Index: src/Boo.Lang.Compiler/TypeSystem/InternalMethod.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/InternalMethod.cs (revision 2443) +++ src/Boo.Lang.Compiler/TypeSystem/InternalMethod.cs (working copy) @@ -409,6 +409,16 @@ override public string ToString() { return _typeSystemServices.GetSignature(this); + } + + IGenericMethodInfo IMethod.GenericMethodInfo + { + get { return null; } } + + IGenericMethodDefinitionInfo IMethod.GenericMethodDefinitionInfo + { + get { return null; } + } } } Index: src/Boo.Lang.Compiler/TypeSystem/ExternalMethod.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/ExternalMethod.cs (revision 2443) +++ src/Boo.Lang.Compiler/TypeSystem/ExternalMethod.cs (working copy) @@ -170,7 +170,7 @@ } } - public string Name + public virtual string Name { get { @@ -178,7 +178,7 @@ } } - public string FullName + public virtual string FullName { get { @@ -288,5 +288,52 @@ { return _typeSystemServices.GetSignature(this); } + +#if NET_2_0 + ExternalGenericMethodDefinitionInfo _genericMethodDefinitionInfo = null; + public IGenericMethodDefinitionInfo GenericMethodDefinitionInfo + { + get + { + if (MethodInfo.IsGenericMethodDefinition) + { + if (_genericMethodDefinitionInfo == null) + { + _genericMethodDefinitionInfo = + new ExternalGenericMethodDefinitionInfo(_typeSystemServices, this); + } + return _genericMethodDefinitionInfo; + } + return null; + } + } + + ExternalGenericMethodInfo _genericMethodInfo = null; + public virtual IGenericMethodInfo GenericMethodInfo + { + get + { + if (MethodInfo.IsGenericMethod) + { + if (_genericMethodInfo == null) + { + _genericMethodInfo = new ExternalGenericMethodInfo(_typeSystemServices, this); + } + return _genericMethodInfo; + } + return null; + } + } +#else + IGenericMethodDefinitionInfo IMethod.GenericMethodDefinitionInfo + { + get { return null; } + } + + IGenericMethodInfo IMethod.GenericMethodInfo + { + get { return null; } + } +#endif } } Index: src/Boo.Lang.Compiler/TypeSystem/GenericTypeMapper.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/GenericTypeMapper.cs (revision 0) +++ src/Boo.Lang.Compiler/TypeSystem/GenericTypeMapper.cs (revision 0) @@ -0,0 +1,192 @@ +#region license +// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Rodrigo B. de Oliveira nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +#if NET_2_0 + +namespace Boo.Lang.Compiler.TypeSystem +{ + using System; + using System.Text; + using System.Reflection; + using System.Collections.Generic; + + public interface ITypeMapper + { + IType MapType(IType sourceType); + } + + /// + /// A basic mapper of generic parameters into arguments. + /// + public class GenericTypeMapper : ITypeMapper + { + #region Data Members + + TypeSystemServices _tss; + Dictionary _map = new Dictionary(); + + #endregion + + #region Constructor + + public GenericTypeMapper(TypeSystemServices tss, IGenericParameter[] parameters, IType[] arguments) + { + _tss = tss; + for (int i = 0; i < parameters.Length; i++) + { + _map.Add(parameters[i], arguments[i]); + } + } + + /// + /// Maps a type involving generic parameters to the corresponding type after substituting concrete + /// arguments for generic parameters. + /// + /// + /// If the source type is a generic parameter, it is mapped to the corresponding argument. + /// If the source type is an open generic type using any of the specified generic parameters, it + /// is mapped to a closed constructed type based on the specified arguments. + /// TODO: complete this + /// + public IType MapType(IType sourceType) + { + if (sourceType == null) + { + return null; + } + + // If sourceType is a reference type, map its element type + if (sourceType.IsByRef) + { + return MapType(sourceType.GetElementType()); + } + + // Map generic parameter to corresponding argument + IGenericParameter gp = sourceType as IGenericParameter; + if (null != gp && _map.ContainsKey(gp)) + { + return _map[gp]; + } + + // Map open constructed type using generic parameters to closed constructed type + // using corresponding arguments + if (null != sourceType.GenericTypeInfo) + { + IType[] mappedArguments = Array.ConvertAll( + sourceType.GenericTypeInfo.GenericArguments, + MapType); + + IType mapped = sourceType.GenericTypeInfo. + GenericDefinition.GenericTypeDefinitionInfo. + MakeGenericType(mappedArguments); + + return mapped; + } + + // Map array types + IArrayType array = (sourceType as IArrayType); + if (array != null) + { + IType elementType = array.GetElementType(); + IType mappedElementType = MapType(elementType); + if (mappedElementType != elementType) + { + return _tss.GetArrayType(mappedElementType, array.GetArrayRank()); + } + } + + // Map callable types + ICallableType callable = sourceType as ICallableType; + if (callable != null) + { + CallableSignature signature = callable.GetSignature(); + + IType returnType = MapType(signature.ReturnType); + IParameter[] parameters = Array.ConvertAll( + signature.Parameters, + delegate(IParameter p) { return new MappedParameter(_tss, (ExternalParameter)p, this); }); + + CallableSignature mappedSignature = new CallableSignature( + parameters, returnType, signature.AcceptVarArgs); + + return _tss.GetCallableType(mappedSignature); + } + + // If source type doesn't require mapping, return it as is + return sourceType; + } + + #endregion + } + + #region class MappedParameter + + /// + /// A parameter in a mixed generic type's method or constructor, or a mixed generic method. + /// + public class MappedParameter : IParameter + { + private ITypeMapper _typeMapper; + private ExternalParameter _baseParameter; + + public MappedParameter(TypeSystemServices tss, ExternalParameter parameter, ITypeMapper typeMapper) + { + _typeMapper = typeMapper; + _baseParameter = parameter; + } + + public bool IsByRef + { + get { return _baseParameter.IsByRef; } + } + + public IType Type + { + get { return _typeMapper.MapType(_baseParameter.Type); } + } + + public string Name + { + get { return _baseParameter.Name; } + } + + public string FullName + { + get { return _baseParameter.FullName; } + } + + public EntityType EntityType + { + get { return EntityType.Parameter; } + } + } + + #endregion +} + +#endif Index: src/Boo.Lang.Compiler/TypeSystem/IEntity.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/IEntity.cs (revision 2443) +++ src/Boo.Lang.Compiler/TypeSystem/IEntity.cs (working copy) @@ -211,13 +211,26 @@ bool FullyConstructed { get; } } + public interface IGenericMethodDefinitionInfo + { + IGenericParameter[] GenericParameters { get; } + IMethod MakeGenericMethod(params IType[] arguments); + } + + public interface IGenericMethodInfo + { + IType[] GenericArguments { get; } + IMethod GenericDefinition { get; } + bool FullyConstructed { get; } + } + public interface IGenericParameter: IType { IType DeclaringType { get; } int GenericParameterPosition { get; } // TODO: Constraints { get; } - } - + } + public interface ICallableType : IType { CallableSignature GetSignature(); @@ -326,6 +339,16 @@ bool IsPInvoke { get; + } + + IGenericMethodInfo GenericMethodInfo + { + get; + } + + IGenericMethodDefinitionInfo GenericMethodDefinitionInfo + { + get; } } Index: src/Boo.Lang.Compiler/TypeSystem/ExternalGenericMethodInfo.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/ExternalGenericMethodInfo.cs (revision 0) +++ src/Boo.Lang.Compiler/TypeSystem/ExternalGenericMethodInfo.cs (revision 0) @@ -0,0 +1,75 @@ +#region license +// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Rodrigo B. de Oliveira nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +#if NET_2_0 + +namespace Boo.Lang.Compiler.TypeSystem +{ + using System; + + public class ExternalGenericMethodInfo : IGenericMethodInfo + { + ExternalMethod _method; + TypeSystemServices _tss; + IType[] _arguments = null; + + public ExternalGenericMethodInfo(TypeSystemServices tss, ExternalMethod method) + { + _method = method; + _tss = tss; + } + + public IMethod GenericDefinition + { + get + { + return _tss.Map(((System.Reflection.MethodInfo)_method.MethodInfo).GetGenericMethodDefinition()); + } + } + + public IType[] GenericArguments + { + get + { + if (_arguments == null) + { + _arguments = Array.ConvertAll( + _method.MethodInfo.GetGenericArguments(), _tss.Map); + } + + return _arguments; + } + } + + public bool FullyConstructed + { + get { return !_method.MethodInfo.ContainsGenericParameters; } + } + } +} +#endif Index: src/Boo.Lang.Compiler/TypeSystem/MixedGenericMethod.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/MixedGenericMethod.cs (revision 0) +++ src/Boo.Lang.Compiler/TypeSystem/MixedGenericMethod.cs (revision 0) @@ -0,0 +1,179 @@ +#region license +// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Rodrigo B. de Oliveira nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +#if NET_2_0 + +namespace Boo.Lang.Compiler.TypeSystem +{ + using System; + using System.Text; + using System.Reflection; + using System.Collections.Generic; + + /// + /// A generic method constructed from an external definition but involving internal parameters. + /// + public class MixedGenericMethod : ExternalMethod, IGenericMethodInfo, ITypeMapper + { + #region Data Members + + ExternalMethod _definition; + IType[] _arguments = null; + GenericTypeMapper _typeMapper; + bool _constructed; + string _name = null; + string _fullName = null; + + #endregion + + #region Constructor + + public MixedGenericMethod(TypeSystemServices tss, ExternalMethod definition, IType[] arguments) : base(tss, definition.MethodInfo) + { + _definition = definition; + _arguments = arguments; + _constructed = IsConstructed(); + _typeMapper = new GenericTypeMapper( + tss, + definition.GenericMethodDefinitionInfo.GenericParameters, + arguments); + } + + #endregion + + #region IGenericMethodInfo members + + public IType[] GenericArguments + { + get { return _arguments; } + } + + public IMethod GenericDefinition + { + get { return _definition; } + } + + public bool FullyConstructed + { + get { return _constructed; } + } + + #endregion + + #region Properties + + public override string Name + { + get + { + if (_name == null) + { + _name = BuildName(false); + } + return _name; + } + } + + public override string FullName + { + get + { + if (_fullName == null) + { + _fullName = BuildName(true); + } + return _fullName; + } + } + + public override IType ReturnType + { + get { return MapType(_definition.ReturnType); } + } + + public override IGenericMethodInfo GenericMethodInfo + { + get { return this; } + } + + #endregion + + #region Private Methods + + private bool IsConstructed() + { + foreach (IType arg in _arguments) + { + if (arg is IGenericParameter) return false; + } + + return true; + } + + private string BuildName(bool full) + { + Converter argumentName = delegate(IType type) + { + return full ? "[" + type.FullName + "]" : type.Name; + }; + + string[] typeNames = Array.ConvertAll(_arguments, argumentName); + + return string.Format( + "{0}[{1}]", + full ? _definition.FullName : _definition.Name, + string.Join(", ", typeNames)); + } + + #endregion + + #region Public Methods + + public override string ToString() + { + return FullName; + } + + public override IParameter[] GetParameters() + { + return Array.ConvertAll( + _definition.GetParameters(), + delegate(IParameter p) { return new MappedParameter( + _typeSystemServices, (ExternalParameter)p, this); }); + } + + public IType MapType(IType sourceType) + { + return _typeMapper.MapType(sourceType); + } + + #endregion + } +} + +#endif Index: src/Boo.Lang.Compiler/TypeSystem/ExternalGenericMethodDefinitionInfo.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/ExternalGenericMethodDefinitionInfo.cs (revision 0) +++ src/Boo.Lang.Compiler/TypeSystem/ExternalGenericMethodDefinitionInfo.cs (revision 0) @@ -0,0 +1,68 @@ +#region license +// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Rodrigo B. de Oliveira nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +#if NET_2_0 + +namespace Boo.Lang.Compiler.TypeSystem +{ + using System; + using System.Collections.Generic; + + public class ExternalGenericMethodDefinitionInfo : AbstractExternalGenericDefinitionInfo, IGenericMethodDefinitionInfo + { + private ExternalMethod _method; + + public ExternalGenericMethodDefinitionInfo(TypeSystemServices tss, ExternalMethod method) : base(tss) + { + _method = method; + } + + public IMethod MakeGenericMethod(IType[] arguments) + { + return (IMethod)MakeGenericEntity(arguments); + } + + protected override Type[] GetActualGenericParameters() + { + return _method.MethodInfo.GetGenericArguments(); + } + + protected override IEntity MakeExternalEntity(Type[] arguments) + { + return _tss.Map(((System.Reflection.MethodInfo)_method.MethodInfo).MakeGenericMethod(arguments)); + } + + protected override IEntity MakeMixedEntity(IType[] arguments) + { + return new MixedGenericMethod(_tss, _method, arguments); + } + } +} + +#endif + Index: src/Boo.Lang.Compiler/TypeSystem/AbstractExternalGenericDefinitionInfo.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/AbstractExternalGenericDefinitionInfo.cs (revision 0) +++ src/Boo.Lang.Compiler/TypeSystem/AbstractExternalGenericDefinitionInfo.cs (revision 0) @@ -0,0 +1,174 @@ +#region license +// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Rodrigo B. de Oliveira nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +#if NET_2_0 + +namespace Boo.Lang.Compiler.TypeSystem +{ + using System; + using System.Collections.Generic; + + public abstract class AbstractExternalGenericDefinitionInfo + { + protected TypeSystemServices _tss; + private IGenericParameter[] _parameters; + private Dictionary _instances = + new Dictionary(new GenericArgumentsComparer()); + + public AbstractExternalGenericDefinitionInfo(TypeSystemServices tss) + { + _tss = tss; + } + + public IGenericParameter[] GenericParameters + { + get + { + if (null == _parameters) + { + _parameters = Array.ConvertAll( + GetActualGenericParameters(), + delegate(Type t) { return (ExternalGenericParameter)_tss.Map(t); }); + } + return _parameters; + } + } + + protected IEntity MakeGenericEntity(IType[] arguments) + { + if (Array.TrueForAll(arguments, IsExternal)) + { + Type[] actualTypes = Array.ConvertAll(arguments, GetSystemType); + + return MakeExternalEntity(actualTypes); + } + else if (_instances.ContainsKey(arguments)) + { + return _instances[arguments]; + } + else + { + IEntity instance = MakeMixedEntity(arguments); + _instances.Add(arguments, instance); + + return instance; + } + } + + protected abstract Type[] GetActualGenericParameters(); + protected abstract IEntity MakeMixedEntity(IType[] arguments); + protected abstract IEntity MakeExternalEntity(Type[] arguments); + + private bool IsExternal(IType type) + { + if (type is ExternalType && !(type is MixedGenericType)) + { + return true; + } + + if (type is ArrayType) + { + return IsExternal(type.GetElementType()); + } + + return false; + } + + private Type GetSystemType(IType type) + { + if (type is ExternalType) + { + return ((ExternalType)type).ActualType; + } + + ArrayType arrayType = type as ArrayType; + if (arrayType != null) + { + Type elementType = GetSystemType(arrayType.GetElementType()); + + return Array.CreateInstance( + elementType, + new int[arrayType.GetArrayRank()]).GetType(); + } + + return null; + } + + private class GenericArgumentsComparer: IEqualityComparer + { + public bool Equals(IType[] x, IType[] y) + { + for (int i = 0; i < x.Length; i++) + { + if ((x[i] == null && y[i] != null) || (!x[i].Equals(y[i]))) + { + return false; + } + } + + return true; + } + + public int GetHashCode(IType[] args) + { + // Make a simple hash code from the hash codes of the arguments + int hash = 0; + for (int i = 0; i < args.Length; i++) + { + hash ^= i ^ args[i].GetHashCode(); + } + + return hash; + } + } + } + + public class ExternalGenericParameter : ExternalType, IGenericParameter + { + public ExternalGenericParameter(TypeSystemServices tss, Type type) : base(tss, type) + { + } + + public int GenericParameterPosition + { + get { return ActualType.GenericParameterPosition; } + } + + public override string FullName + { + get + { + // FIXME: use DeclaringMethod rather than DeclaringType for + // parameters of generic methods + return string.Format("{0}.{1}", DeclaringType.FullName, Name); + } + } + } +} +#endif + Index: src/Boo.Lang.Compiler/TypeSystem/ExternalGenericTypeInfo.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/ExternalGenericTypeInfo.cs (revision 2443) +++ src/Boo.Lang.Compiler/TypeSystem/ExternalGenericTypeInfo.cs (working copy) @@ -34,18 +34,24 @@ public class ExternalGenericTypeInfo : IGenericTypeInfo { - TypeSystemServices _tss; ExternalType _type; + TypeSystemServices _tss; IType[] _arguments = null; - bool _constructed; public ExternalGenericTypeInfo(TypeSystemServices tss, ExternalType type) { - _tss = tss; _type = type; - _constructed = !_type.ActualType.ContainsGenericParameters; + _tss = tss; } + public IType GenericDefinition + { + get + { + return _tss.Map(_type.ActualType.GetGenericTypeDefinition()); + } + } + public IType[] GenericArguments { get @@ -53,26 +59,17 @@ if (_arguments == null) { _arguments = Array.ConvertAll( - _type.ActualType.GetGenericArguments(), - _tss.Map); + _type.ActualType.GetGenericArguments(), _tss.Map); } return _arguments; } } - - public IType GenericDefinition + + public bool FullyConstructed { - get - { - return _tss.Map(_type.ActualType.GetGenericTypeDefinition()); - } + get { return !_type.ActualType.ContainsGenericParameters; } } - - public bool FullyConstructed - { - get { return _constructed; } - } } } #endif Index: src/Boo.Lang.Compiler/TypeSystem/MixedGenericType.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/MixedGenericType.cs (revision 2443) +++ src/Boo.Lang.Compiler/TypeSystem/MixedGenericType.cs (working copy) @@ -1,4 +1,4 @@ -#region license +#region license // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org) // All rights reserved. // @@ -38,13 +38,14 @@ /// /// A generic type constructed from an external definition but involving internal parameters. /// - public class MixedGenericType : ExternalType, IGenericTypeInfo + public class MixedGenericType : ExternalType, IGenericTypeInfo, ITypeMapper { #region Data Members ExternalType _definition; - IType[] _arguments = null; - bool _constructed; + IType[] _arguments; + GenericTypeMapper _typeMapper; + bool _constructed; string _name = null; string _fullName = null; Dictionary _mappedMembers = new Dictionary(); @@ -58,6 +59,10 @@ _definition = definition; _arguments = arguments; _constructed = IsConstructed(); + _typeMapper = new GenericTypeMapper( + tss, + definition.GenericTypeDefinitionInfo.GenericParameters, + arguments); } #endregion @@ -117,6 +122,11 @@ } } + public GenericTypeMapper TypeMapper + { + get { return _typeMapper; } + } + #endregion #region Private Methods @@ -222,68 +232,16 @@ #region Mapping methods - /// - /// Maps a type involving generic parameters to the corresponding type after substituting concrete - /// arguments for generic parameters. - /// - /// - /// If the source type is a generic parameter of this type's definition, it is mapped to the - /// corresponding argument. - /// If the source type is an open generic type using parameters from the type's definition, it - /// is mapped to a closed constructed type based on this type's arguments. - /// If the source type is an array of a generic parameter of this type's definition, it is mapped - /// to the array type of the corresponding argument, of the same rank. - /// - protected IType MapType(IType sourceType) + public IType MapType(IType sourceType) { - if (sourceType == null) - { - return null; - } - - // If sourceType is a reference type, map its element type - if (sourceType.IsByRef) - { - return MapType(sourceType.GetElementType()); - } - - // Map generic parameter to corresponding argument - IGenericParameter gp = sourceType as IGenericParameter; - if (null != gp && gp.DeclaringType == _definition) - { - return GenericArguments[gp.GenericParameterPosition]; - } - // Map own definition to this mixed type if (sourceType == GenericDefinition) { return this; } - // Map open constructed type using generic parameters to closed constructed type - // using corresponding arguments - if (null != sourceType.GenericTypeInfo) - { - IType[] mappedArguments = Array.ConvertAll( - sourceType.GenericTypeInfo.GenericArguments, - MapType); - - IType mapped = sourceType.GenericTypeInfo. - GenericDefinition.GenericTypeDefinitionInfo. - MakeGenericType(mappedArguments); - - return mapped; - } - - // Map array of generic parameter to array of corresponding argument - IArrayType array = (sourceType as IArrayType); - if (array != null) - { - return _typeSystemServices.GetArrayType(MapType(array.GetElementType()), array.GetArrayRank()); - } - - // If source type doesn't require mapping, return it as is - return sourceType; + // For all other cases use the generic type mapper + return _typeMapper.MapType(sourceType); } /// @@ -353,7 +311,6 @@ public override IType DeclaringType { - // get { return _parentType; } get { return _parentType.MapType(base.DeclaringType); } } @@ -377,7 +334,7 @@ { return new MappedParameter(_typeSystemServices, (ExternalParameter)p, _parentType); }); - } + } } #endregion @@ -414,50 +371,6 @@ #endregion - #region class MappedParameter - - /// - /// A parameter in a method or constructor of a mixed generic type. - /// - public class MappedParameter : IParameter - { - private MixedGenericType _parentType; - private ExternalParameter _baseParameter; - - public MappedParameter(TypeSystemServices tss, ExternalParameter parameter, MixedGenericType parentType) - { - _parentType = parentType; - _baseParameter = parameter; - } - - public bool IsByRef - { - get { return _baseParameter.IsByRef; } - } - - public IType Type - { - get { return _parentType.MapType(_baseParameter.Type); } - } - - public string Name - { - get { return _baseParameter.Name; } - } - - public string FullName - { - get { return _baseParameter.FullName; } - } - - public EntityType EntityType - { - get { return EntityType.Parameter; } - } - } - - #endregion - #region class MappedProperty public class MappedProperty : ExternalProperty Index: src/Boo.Lang.Compiler/TypeSystem/ExternalGenericTypeDefinitionInfo.cs =================================================================== --- src/Boo.Lang.Compiler/TypeSystem/ExternalGenericTypeDefinitionInfo.cs (revision 2443) +++ src/Boo.Lang.Compiler/TypeSystem/ExternalGenericTypeDefinitionInfo.cs (working copy) @@ -33,56 +33,31 @@ using System; using System.Collections.Generic; - public class ExternalGenericTypeDefinitionInfo : IGenericTypeDefinitionInfo + public class ExternalGenericTypeDefinitionInfo : AbstractExternalGenericDefinitionInfo, IGenericTypeDefinitionInfo { private ExternalType _type; - private TypeSystemServices _tss; - private IGenericParameter[] _parameters; - private IDictionary _instances; - public ExternalGenericTypeDefinitionInfo(TypeSystemServices tss, ExternalType type) + public ExternalGenericTypeDefinitionInfo(TypeSystemServices tss, ExternalType type) : base(tss) { - _tss = tss; _type = type; - _instances = new Dictionary(new GenericArgumentsComparer()); } - public IGenericParameter[] GenericParameters - { - get - { - if (null == _parameters) - { - _parameters = Array.ConvertAll( - _type.ActualType.GetGenericArguments(), - delegate(Type t) { return new ExternalGenericParameter(_tss, t); }); - } - return _parameters; - } - } - public IType MakeGenericType(IType[] arguments) - { - if (Array.TrueForAll(arguments, IsExternal)) - { - Type[] actualTypes = Array.ConvertAll(arguments, GetSystemType); - - return _tss.Map(_type.ActualType.MakeGenericType(actualTypes)); - } - else if (_instances.ContainsKey(arguments)) - { - return _instances[arguments]; - } - else - { - IType instance = CreateMixedType(arguments); - _instances.Add(arguments, instance); - - return instance; - } + { + return (IType)MakeGenericEntity(arguments); } + + protected override Type[] GetActualGenericParameters() + { + return _type.ActualType.GetGenericArguments(); + } + + protected override IEntity MakeExternalEntity(Type[] arguments) + { + return _tss.Map(_type.ActualType.MakeGenericType(arguments)); + } - private IType CreateMixedType(IType[] arguments) + protected override IEntity MakeMixedEntity(IType[] arguments) { ExternalCallableType callable = _type as ExternalCallableType; if (null != callable) @@ -93,92 +68,8 @@ { return new MixedGenericType(_tss, _type, arguments); } - } - - private bool IsExternal(IType type) - { - if (type is ExternalType && !(type is MixedGenericType)) - { - return true; - } - - if (type is ArrayType) - { - return IsExternal(type.GetElementType()); - } - - return false; - } - - private Type GetSystemType(IType type) - { - if (type is ExternalType) - { - return ((ExternalType)type).ActualType; - } - - ArrayType arrayType = type as ArrayType; - if (arrayType != null) - { - Type elementType = GetSystemType(arrayType.GetElementType()); - - return Array.CreateInstance( - elementType, - new int[arrayType.GetArrayRank()]).GetType(); - } - - return null; - } - - private class GenericArgumentsComparer: IEqualityComparer - { - public bool Equals(IType[] x, IType[] y) - { - for (int i = 0; i < x.Length; i++) - { - if ((x[i] == null && y[i] != null) || (!x[i].Equals(y[i]))) - { - return false; - } - } - - return true; - } - - public int GetHashCode(IType[] args) - { - // Make a simple hash code from the hash codes of the arguments - int hash = 0; - for (int i = 0; i < args.Length; i++) - { - hash ^= i ^ args[i].GetHashCode(); - } - - return hash; - } - } + } } - - - public class ExternalGenericParameter : ExternalType, IGenericParameter - { - public ExternalGenericParameter(TypeSystemServices tss, Type type) : base(tss, type) - { - } - - public int GenericParameterPosition - { - get { return ActualType.GenericParameterPosition; } - } - - public override string FullName - { - get - { - return string.Format("{0}.{1}", DeclaringType.FullName, Name); - } - } - } } #endif Index: src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (revision 2443) +++ src/Boo.Lang.Compiler/Steps/ProcessMethodBodies.cs (working copy) @@ -2101,10 +2101,20 @@ return; } - IType genericType = ((IType)node.Target.Entity).GenericTypeDefinitionInfo.MakeGenericType(GetGenericArguments(node)); - Bind(node, genericType); - BindExpressionType(node, this.TypeSystemServices.TypeType); - + switch (node.Target.Entity.EntityType) + { + case EntityType.Type: + IType genericType = ((IType)node.Target.Entity).GenericTypeDefinitionInfo.MakeGenericType(GetGenericArguments(node)); + Bind(node, genericType); + BindExpressionType(node, this.TypeSystemServices.TypeType); + break; + + case EntityType.Method: + IMethod genericMethod = ((IMethod)node.Target.Entity).GenericMethodDefinitionInfo.MakeGenericMethod(GetGenericArguments(node)); + Bind(node, genericMethod); + BindExpressionType(node, genericMethod.ReturnType); + break; + } } private IType[] GetGenericArguments(GenericReferenceExpression node) @@ -2122,15 +2132,31 @@ { IEntity entity = node.Target.Entity; IType type = entity as IType; - if (type == null || type.GenericTypeDefinitionInfo == null) + IMethod method = entity as IMethod; + IGenericParameter[] parameters = null; + + // Test for a generic type definition + if (type != null && type.GenericTypeDefinitionInfo != null) { + parameters = type.GenericTypeDefinitionInfo.GenericParameters; + } + // Test for a generic method definition + else if (method != null && method.GenericMethodDefinitionInfo != null) + { + parameters = method.GenericMethodDefinitionInfo.GenericParameters; + } + + if (parameters == null) + { return CompilerErrorFactory.NotAGenericDefinition(AstUtil.GetMemberAnchor(node.Target), entity.FullName); } - IGenericParameter[] parameters = type.GenericTypeDefinitionInfo.GenericParameters; - if (parameters.Length != node.GenericArguments.Count) return CompilerErrorFactory.GenericDefinitionArgumentCount(AstUtil.GetMemberAnchor(node.Target), entity.FullName, parameters.Length); + if (parameters.Length != node.GenericArguments.Count) + { + return CompilerErrorFactory.GenericDefinitionArgumentCount(AstUtil.GetMemberAnchor(node.Target), entity.FullName, parameters.Length); + } - return null; + return null; } override public void OnReferenceExpression(ReferenceExpression node) Index: src/Boo.Lang.Compiler/Steps/EmitAssembly.cs =================================================================== --- src/Boo.Lang.Compiler/Steps/EmitAssembly.cs (revision 2443) +++ src/Boo.Lang.Compiler/Steps/EmitAssembly.cs (working copy) @@ -3707,6 +3707,13 @@ if (null != mapped && mapped.MethodInfo.DeclaringType.IsGenericType) { return MapGenericMethod(mapped.DeclaringType, (MethodInfo)mapped.MethodInfo); + } + + // If method is a mixed generic method, get its mapped MethodInfo + MixedGenericMethod generic = entity as MixedGenericMethod; + if (null != generic) + { + return MapGenericMethod(generic); } #endif ExternalMethod external = entity as ExternalMethod; @@ -3759,6 +3766,18 @@ } /// + /// Maps a generic method to its constructed version. + /// + private MethodInfo MapGenericMethod(MixedGenericMethod method) + { + Type[] arguments = Array.ConvertAll( + method.GenericArguments, + GetSystemType); + + return ((MethodInfo)method.MethodInfo).MakeGenericMethod(arguments); + } + + /// /// Maps a field declared on a generic type definition or an open constructed type /// to the corresponding field on a closed constructed type. ///