BOO-988: Added else block to the for and while statements, and include a suite of...
[boo.git] / src / Boo.Lang.Compiler / TypeSystem / GenericMapping.cs
blob111a0a0a352b0aeeadaf25f85f2e8eaf7ac8809b
1 #region license
2 // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #endregion
29 namespace Boo.Lang.Compiler.TypeSystem
31 using System;
32 using System.Text;
33 using System.Reflection;
34 using System.Collections.Generic;
36 /// <summary>
37 /// Maps entities onto their constructed counterparts, substituting type arguments for generic parameters.
38 /// </summary>
39 public class GenericMapping
41 TypeSystemServices _tss;
42 IDictionary<IGenericParameter, IType> _map = new Dictionary<IGenericParameter, IType>();
43 IDictionary<IEntity, IEntity> _cache = new Dictionary<IEntity, IEntity>();
44 IEntity _constructedOwner = null;
45 IEntity _genericSource = null;
47 /// <summary>
48 /// Constructs a new generic mapping between a generic type and one of its constructed types.
49 /// </summary>
50 public GenericMapping(TypeSystemServices tss, IType constructedType, IType[] arguments)
51 : this(tss, constructedType.ConstructedInfo.GenericDefinition.GenericInfo.GenericParameters, arguments)
53 _constructedOwner = constructedType;
54 _genericSource = constructedType.ConstructedInfo.GenericDefinition;
57 /// <summary>
58 /// Constructs a new generic mapping between a generic method and one of its constructed methods.
59 /// </summary>
60 public GenericMapping(TypeSystemServices tss, IMethod constructedMethod, IType[] arguments)
61 : this(tss, constructedMethod.ConstructedInfo.GenericDefinition.GenericInfo.GenericParameters, arguments)
63 _constructedOwner = constructedMethod;
64 _genericSource = constructedMethod.ConstructedInfo.GenericDefinition;
67 /// <summary>
68 /// Constrcuts a new GenericMapping for a specific mapping of generic parameters to type arguments.
69 /// </summary>
70 /// <param name="parameters">The generic parameters that should be mapped.</param>
71 /// <param name="arguments">The type arguments to map generic parameters to.</param>
72 protected GenericMapping(TypeSystemServices tss, IGenericParameter[] parameters, IType[] arguments)
74 _tss = tss;
75 for (int i = 0; i < parameters.Length; i++)
77 _map.Add(parameters[i], arguments[i]);
81 /// <summary>
82 /// Maps a type involving generic parameters to the corresponding type after substituting concrete
83 /// arguments for generic parameters.
84 /// </summary>
85 /// <remarks>
86 /// If the source type is a generic parameter, it is mapped to the corresponding argument.
87 /// If the source type is an open generic type using any of the specified generic parameters, it
88 /// is mapped to a closed constructed type based on the specified arguments.
89 /// </remarks>
90 protected virtual IType MapType(IType sourceType)
92 if (sourceType == null)
94 return null;
97 // Strip reference types
98 if (sourceType.IsByRef)
100 return MapType(sourceType.GetElementType());
103 // Map generic parameter to corresponding argument
104 IGenericParameter gp = sourceType as IGenericParameter;
105 if (null != gp && _map.ContainsKey(gp))
107 return _map[gp];
110 // Map open constructed type using generic parameters to closed constructed type
111 // using corresponding arguments
112 if (null != sourceType.ConstructedInfo)
114 IType[] mappedArguments = Array.ConvertAll<IType, IType>(
115 sourceType.ConstructedInfo.GenericArguments,
116 MapType);
118 IType mapped = sourceType.ConstructedInfo.
119 GenericDefinition.GenericInfo.
120 ConstructType(mappedArguments);
122 return mapped;
125 // TODO: Map nested types
126 // GenericType[of T].NestedType => GenericType[of int].NestedType
128 // Map array types
129 IArrayType array = (sourceType as IArrayType);
130 if (array != null)
132 IType elementType = array.GetElementType();
133 IType mappedElementType = MapType(elementType);
134 if (mappedElementType != elementType)
136 return _tss.GetArrayType(mappedElementType, array.GetArrayRank());
140 // Map callable types
141 ICallableType callable = sourceType as ICallableType;
142 if (callable != null && EntityNeedsMapping(callable))
144 CallableSignature signature = callable.GetSignature();
146 IType returnType = MapType(signature.ReturnType);
147 IParameter[] parameters = Map(signature.Parameters);
149 CallableSignature mappedSignature = new CallableSignature(
150 parameters, returnType, signature.AcceptVarArgs);
152 return _tss.GetCallableType(mappedSignature);
155 // If source type doesn't require mapping, return it as is
156 return sourceType;
159 public bool EntityNeedsMapping(IEntity entity)
161 if (entity is ICallableType)
163 if (entity is ExternalCallableType)
165 return false;
168 ICallableType callable = entity as ICallableType;
170 if (callable.BaseType == _tss.MulticastDelegateType
171 || callable.BaseType.IsSubclassOf(_tss.MulticastDelegateType))
173 return callable.ConstructedInfo != null
174 || callable.GenericInfo != null;
176 return true;
178 if (entity is IMember)
180 IMember member = entity as IMember;
181 return member.DeclaringType.ConstructedInfo != null
182 || member.DeclaringType.GenericInfo != null;
184 if (entity is IConstructedTypeInfo)
186 return true;
188 return false;
191 /// <summary>
192 /// Maps a type member involving generic arguments to its constructed counterpart, after substituting
193 /// concrete types for generic arguments.
194 /// </summary>
195 public IEntity Map(IEntity source)
197 if (source == null)
198 return null;
200 // Map generic source to the constructed owner of this mapping
201 if (source == _genericSource)
203 return _constructedOwner;
206 // Use cache if possible
207 if (_cache.ContainsKey(source))
209 return _cache[source];
212 // Map entity based on its entity type
213 IEntity mapped = null;
214 switch (source.EntityType)
216 case EntityType.Ambiguous:
217 mapped = MapAmbiguousEntity((Ambiguous)source);
218 break;
220 case EntityType.Method:
221 mapped = new GenericMappedMethod(_tss, ((IMethod)source), this);
222 break;
224 case EntityType.Constructor:
225 mapped = new GenericMappedConstructor(_tss, ((IConstructor)source), this);
226 break;
228 case EntityType.Field:
229 mapped = new GenericMappedField(_tss, ((IField)source), this);
230 break;
232 case EntityType.Property:
233 mapped = new GenericMappedProperty(_tss, ((IProperty)source), this);
234 break;
236 case EntityType.Event:
237 mapped = new GenericMappedEvent(_tss, ((IEvent)source), this);
238 break;
240 case EntityType.Parameter:
241 mapped = new GenericMappedParameter((IParameter)source, this);
242 break;
244 case EntityType.Array:
245 case EntityType.Type:
246 mapped = MapType((IType)source);
247 break;
249 default:
250 return source;
253 // Cache mapped result and return it
254 _cache[source] = mapped;
255 return mapped;
258 /// <summary>
259 /// Maps a method on a generic type definition to its constructed counterpart.
260 /// </summary>
261 public IMethod Map(IMethod source)
263 return (IMethod)Map((IEntity)source);
266 /// <summary>
267 /// Maps a constructor on a generic type definition to its constructed counterpart.
268 /// </summary>
269 public IConstructor Map(IConstructor source)
271 return (IConstructor)Map((IEntity)source);
274 /// <summary>
275 /// Maps a field on a generic type definition to its constructed counterpart.
276 /// </summary>
277 public IField Map(IField source)
279 return (IField)Map((IEntity)source);
282 /// <summary>
283 /// Maps a property on a generic type definition to its constructed counterpart.
284 /// </summary>
285 public IProperty Map(IProperty source)
287 return (IProperty)Map((IEntity)source);
290 /// <summary>
291 /// Maps an event on a generic type definition to its constructed counterpart.
292 /// </summary>
293 public IEvent Map(IEvent source)
295 return (IEvent)Map((IEvent)source);
298 /// <summary>
299 /// Maps a type involving generic parameters to its constructed counterpart.
300 /// </summary>
301 public IType Map(IType source)
303 return (IType)Map((IEntity)source);
306 /// <summary>
307 /// Maps a parameter in a generic, constructed or mapped method to its constructed counterpart.
308 /// </summary>
309 public IParameter Map(IParameter source)
311 return (IParameter)Map((IEntity)source);
314 /// <summary>
315 /// Maps an array of parameters in a generic, constructed or mapped method to their constructed counterparts.
316 /// </summary>
317 public IParameter[] Map(IParameter[] sources)
319 return Array.ConvertAll<IParameter, IParameter>(sources, Map);
322 private IEntity MapAmbiguousEntity(Ambiguous source)
324 // Map each individual entity in the ambiguous list
325 return new Ambiguous(Array.ConvertAll<IEntity, IEntity>(source.Entities, Map));
328 /// <summary>
329 /// Gets the method from which the specified method was mapped.
330 /// </summary>
331 public IMethod UnMap(IMethod method)
333 GenericMappedMethod mapped = method as GenericMappedMethod;
334 if (mapped == null)
336 return null;
338 return mapped.Source;