2 // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
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.
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.
29 namespace Boo
.Lang
.Compiler
.TypeSystem
33 using System
.Reflection
;
34 using System
.Collections
.Generic
;
37 /// Maps entities onto their constructed counterparts, substituting type arguments for generic parameters.
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;
48 /// Constructs a new generic mapping between a generic type and one of its constructed types.
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
;
58 /// Constructs a new generic mapping between a generic method and one of its constructed methods.
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
;
68 /// Constrcuts a new GenericMapping for a specific mapping of generic parameters to type arguments.
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
)
75 for (int i
= 0; i
< parameters
.Length
; i
++)
77 _map
.Add(parameters
[i
], arguments
[i
]);
82 /// Maps a type involving generic parameters to the corresponding type after substituting concrete
83 /// arguments for generic parameters.
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.
90 protected virtual IType
MapType(IType sourceType
)
92 if (sourceType
== 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
))
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
,
118 IType mapped
= sourceType
.ConstructedInfo
.
119 GenericDefinition
.GenericInfo
.
120 ConstructType(mappedArguments
);
125 // TODO: Map nested types
126 // GenericType[of T].NestedType => GenericType[of int].NestedType
129 IArrayType array
= (sourceType
as IArrayType
);
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
159 public bool EntityNeedsMapping(IEntity entity
)
161 if (entity
is ICallableType
)
163 if (entity
is ExternalCallableType
)
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;
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
)
192 /// Maps a type member involving generic arguments to its constructed counterpart, after substituting
193 /// concrete types for generic arguments.
195 public IEntity
Map(IEntity source
)
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
);
220 case EntityType
.Method
:
221 mapped
= new GenericMappedMethod(_tss
, ((IMethod
)source
), this);
224 case EntityType
.Constructor
:
225 mapped
= new GenericMappedConstructor(_tss
, ((IConstructor
)source
), this);
228 case EntityType
.Field
:
229 mapped
= new GenericMappedField(_tss
, ((IField
)source
), this);
232 case EntityType
.Property
:
233 mapped
= new GenericMappedProperty(_tss
, ((IProperty
)source
), this);
236 case EntityType
.Event
:
237 mapped
= new GenericMappedEvent(_tss
, ((IEvent
)source
), this);
240 case EntityType
.Parameter
:
241 mapped
= new GenericMappedParameter((IParameter
)source
, this);
244 case EntityType
.Array
:
245 case EntityType
.Type
:
246 mapped
= MapType((IType
)source
);
253 // Cache mapped result and return it
254 _cache
[source
] = mapped
;
259 /// Maps a method on a generic type definition to its constructed counterpart.
261 public IMethod
Map(IMethod source
)
263 return (IMethod
)Map((IEntity
)source
);
267 /// Maps a constructor on a generic type definition to its constructed counterpart.
269 public IConstructor
Map(IConstructor source
)
271 return (IConstructor
)Map((IEntity
)source
);
275 /// Maps a field on a generic type definition to its constructed counterpart.
277 public IField
Map(IField source
)
279 return (IField
)Map((IEntity
)source
);
283 /// Maps a property on a generic type definition to its constructed counterpart.
285 public IProperty
Map(IProperty source
)
287 return (IProperty
)Map((IEntity
)source
);
291 /// Maps an event on a generic type definition to its constructed counterpart.
293 public IEvent
Map(IEvent source
)
295 return (IEvent
)Map((IEvent
)source
);
299 /// Maps a type involving generic parameters to its constructed counterpart.
301 public IType
Map(IType source
)
303 return (IType
)Map((IEntity
)source
);
307 /// Maps a parameter in a generic, constructed or mapped method to its constructed counterpart.
309 public IParameter
Map(IParameter source
)
311 return (IParameter
)Map((IEntity
)source
);
315 /// Maps an array of parameters in a generic, constructed or mapped method to their constructed counterparts.
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
));
329 /// Gets the method from which the specified method was mapped.
331 public IMethod
UnMap(IMethod method
)
333 GenericMappedMethod mapped
= method
as GenericMappedMethod
;
338 return mapped
.Source
;