No significant changes. Adding a few more tests to the primitives test case and...
[boo.git] / src / Boo.Lang.Compiler / TypeSystem / TypeSystemServices.cs
blobf9dee851f0612d4524546071072defc930949767
1 #region license
2 // Copyright (c) 2004, 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.
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.Collections;
33 using System.Reflection;
34 using System.Text;
35 using Boo.Lang.Compiler.Ast;
36 using Attribute = Boo.Lang.Compiler.Ast.Attribute;
37 using Module = Boo.Lang.Compiler.Ast.Module;
39 public class TypeSystemServices
41 public DuckTypeImpl DuckType;
43 public ExternalType IQuackFuType;
45 public ExternalType ExceptionType;
47 public ExternalType ApplicationExceptionType;
49 public ExternalType MulticastDelegateType;
51 public ExternalType DelegateType;
53 public ExternalType IntPtrType;
55 public ExternalType UIntPtrType;
57 public ExternalType ObjectType;
59 public ExternalType ValueTypeType;
61 public ExternalType EnumType;
63 public ExternalType RegexType;
65 public ExternalType ArrayType;
67 public ExternalType TypeType;
69 public IArrayType ObjectArrayType;
71 public ExternalType VoidType;
73 public ExternalType StringType;
75 public ExternalType BoolType;
77 public ExternalType CharType;
79 public ExternalType SByteType;
81 public ExternalType ByteType;
83 public ExternalType ShortType;
85 public ExternalType UShortType;
87 public ExternalType IntType;
89 public ExternalType UIntType;
91 public ExternalType LongType;
93 public ExternalType ULongType;
95 public ExternalType SingleType;
97 public ExternalType DoubleType;
99 public ExternalType DecimalType;
101 public ExternalType TimeSpanType;
103 protected ExternalType DateTimeType;
105 public ExternalType RuntimeServicesType;
107 public ExternalType BuiltinsType;
109 public ExternalType ListType;
111 public ExternalType HashType;
113 public ExternalType ICallableType;
115 public ExternalType IEnumerableType;
117 public ExternalType IEnumeratorType;
119 public ExternalType IEnumerableGenericType;
121 public ExternalType IEnumeratorGenericType;
123 public ExternalType ICollectionType;
125 public ExternalType IListType;
127 public ExternalType IDictionaryType;
129 public ExternalType SystemAttribute;
131 public ExternalType ConditionalAttribute;
133 protected Hashtable _primitives = new Hashtable();
135 protected Hashtable _entityCache = new Hashtable();
137 protected Hashtable _arrayCache = new Hashtable();
139 public static readonly IType ErrorEntity = Error.Default;
141 public readonly BooCodeBuilder CodeBuilder;
143 private StringBuilder _buffer = new StringBuilder();
145 private Module _compilerGeneratedTypesModule;
147 private Module _compilerGeneratedExtensionsModule;
149 private ClassDefinition _compilerGeneratedExtensionsClass;
151 protected readonly CompilerContext _context;
153 private readonly AnonymousCallablesManager _anonymousCallablesManager;
155 private readonly GenericsServices _genericsServices;
157 public TypeSystemServices() : this(new CompilerContext())
161 public TypeSystemServices(CompilerContext context)
163 if (null == context) throw new ArgumentNullException("context");
165 _context = context;
166 _anonymousCallablesManager = new AnonymousCallablesManager(this);
167 _genericsServices = new GenericsServices(context);
169 CodeBuilder = new BooCodeBuilder(this);
171 Cache(typeof(Builtins.duck), DuckType = new DuckTypeImpl(this));
172 Cache(IQuackFuType = new ExternalType(this, typeof(IQuackFu)));
173 Cache(VoidType = new VoidTypeImpl(this));
174 Cache(ObjectType = new ExternalType(this, Types.Object));
175 Cache(RegexType = new ExternalType(this, Types.Regex));
176 Cache(ValueTypeType = new ExternalType(this, typeof(ValueType)));
177 Cache(EnumType = new ExternalType(this, typeof(Enum)));
178 Cache(ArrayType = new ExternalType(this, Types.Array));
179 Cache(TypeType = new ExternalType(this, Types.Type));
180 Cache(StringType = new ExternalType(this, Types.String));
181 Cache(BoolType = new ExternalType(this, Types.Bool));
182 Cache(SByteType = new ExternalType(this, Types.SByte));
183 Cache(CharType = new ExternalType(this, Types.Char));
184 Cache(ShortType = new ExternalType(this, Types.Short));
185 Cache(IntType = new ExternalType(this, Types.Int));
186 Cache(LongType = new ExternalType(this, Types.Long));
187 Cache(ByteType = new ExternalType(this, Types.Byte));
188 Cache(UShortType = new ExternalType(this, Types.UShort));
189 Cache(UIntType = new ExternalType(this, Types.UInt));
190 Cache(ULongType = new ExternalType(this, Types.ULong));
191 Cache(SingleType = new ExternalType(this, Types.Single));
192 Cache(DoubleType = new ExternalType(this, Types.Double));
193 Cache(DecimalType = new ExternalType(this, Types.Decimal));
194 Cache(TimeSpanType = new ExternalType(this, Types.TimeSpan));
195 Cache(DateTimeType = new ExternalType(this, Types.DateTime));
196 Cache(RuntimeServicesType = new ExternalType(this, Types.RuntimeServices));
197 Cache(BuiltinsType = new ExternalType(this, Types.Builtins));
198 Cache(ListType = new ExternalType(this, Types.List));
199 Cache(HashType = new ExternalType(this, Types.Hash));
200 Cache(ICallableType = new ExternalType(this, Types.ICallable));
201 Cache(IEnumerableType = new ExternalType(this, Types.IEnumerable));
202 Cache(IEnumeratorType = new ExternalType(this, typeof(IEnumerator)));
203 Cache(ICollectionType = new ExternalType(this, Types.ICollection));
204 Cache(IListType = new ExternalType(this, Types.IList));
205 Cache(IDictionaryType = new ExternalType(this, Types.IDictionary));
206 Cache(ApplicationExceptionType = new ExternalType(this, Types.ApplicationException));
207 Cache(ExceptionType = new ExternalType(this, Types.Exception));
208 Cache(IntPtrType = new ExternalType(this, Types.IntPtr));
209 Cache(UIntPtrType = new ExternalType(this, Types.UIntPtr));
210 Cache(MulticastDelegateType = new ExternalType(this, Types.MulticastDelegate));
211 Cache(DelegateType = new ExternalType(this, Types.Delegate));
212 Cache(SystemAttribute = new ExternalType(this, typeof(System.Attribute)));
213 Cache(ConditionalAttribute = new ExternalType(this, typeof(System.Diagnostics.ConditionalAttribute)));
214 Cache(IEnumerableGenericType = new ExternalType(this, typeof(System.Collections.Generic.IEnumerable<>)));
215 Cache(IEnumeratorGenericType = new ExternalType(this, typeof(System.Collections.Generic.IEnumerator<>)));
217 ObjectArrayType = GetArrayType(ObjectType, 1);
219 PreparePrimitives();
220 PrepareBuiltinFunctions();
224 public CompilerContext Context
226 get { return _context; }
229 public GenericsServices GenericsServices
231 get { return _genericsServices; }
234 public IType GetMostGenericType(IType current, IType candidate)
236 if (current.IsAssignableFrom(candidate))
238 return current;
241 if (candidate.IsAssignableFrom(current))
243 return candidate;
246 if (IsNumberOrBool(current) && IsNumberOrBool(candidate))
248 return GetPromotedNumberType(current, candidate);
251 if (IsCallableType(current) && IsCallableType(candidate))
253 return ICallableType;
256 if (current.IsClass && candidate.IsClass)
258 if (current == ObjectType || candidate == ObjectType)
260 return ObjectType;
262 if (current.GetTypeDepth() < candidate.GetTypeDepth())
264 return GetMostGenericType(current.BaseType, candidate);
266 return GetMostGenericType(current, candidate.BaseType);
268 return ObjectType;
271 public IType GetPromotedNumberType(IType left, IType right)
273 if (left == DecimalType ||
274 right == DecimalType)
276 return DecimalType;
278 if (left == DoubleType ||
279 right == DoubleType)
281 return DoubleType;
283 if (left == SingleType ||
284 right == SingleType)
286 return SingleType;
288 if (left == ULongType)
290 if (right == SByteType ||
291 right == ShortType ||
292 right == IntType ||
293 right == LongType)
295 // This is against the C# spec but allows expressions like:
296 // ulong x = 4
297 // y = x + 1
298 // y will be long.
299 // C# disallows mixing ulongs and signed numbers
300 // but in the above case it promotes the constant to ulong
301 // and the result is ulong.
302 // Since its too late here to promote the constant,
303 // maybe we should return LongType. I didn't chose ULongType
304 // because in other cases <unsigned> <op> <signed> returns <signed>.
305 return LongType;
307 return ULongType;
309 if (right == ULongType)
311 if (left == SByteType ||
312 left == ShortType ||
313 left == IntType ||
314 left == LongType)
316 // This is against the C# spec but allows expressions like:
317 // ulong x = 4
318 // y = 1 + x
319 // y will be long.
320 // C# disallows mixing ulongs and signed numbers
321 // but in the above case it promotes the constant to ulong
322 // and the result is ulong.
323 // Since its too late here to promote the constant,
324 // maybe we should return LongType. I didn't chose ULongType
325 // because in other cases <signed> <op> <unsigned> returns <signed>.
326 return LongType;
328 return ULongType;
330 if (left == LongType ||
331 right == LongType)
333 return LongType;
335 if (left == UIntType)
337 if (right == SByteType ||
338 right == ShortType ||
339 right == IntType)
341 // This is allowed per C# spec and y is long:
342 // uint x = 4
343 // y = x + 1
344 // C# promotes <uint> <op> <signed> to <long> also
345 // but in the above case it promotes the constant to uint first
346 // and the result of "x + 1" is uint.
347 // Since its too late here to promote the constant,
348 // "y = x + 1" will be long in boo.
349 return LongType;
351 return UIntType;
353 if (right == UIntType)
355 if (left == SByteType ||
356 left == ShortType ||
357 left == IntType)
359 // This is allowed per C# spec and y is long:
360 // uint x = 4
361 // y = 1 + x
362 // C# promotes <signed> <op> <uint> to <long> also
363 // but in the above case it promotes the constant to uint first
364 // and the result of "1 + x" is uint.
365 // Since its too late here to promote the constant,
366 // "y = x + 1" will be long in boo.
367 return LongType;
369 return UIntType;
371 if (left == IntType ||
372 right == IntType ||
373 left == ShortType ||
374 right == ShortType ||
375 left == UShortType ||
376 right == UShortType ||
377 left == ByteType ||
378 right == ByteType ||
379 left == SByteType ||
380 right == SByteType)
382 return IntType;
384 return left;
387 public static bool IsReadOnlyField(IField field)
389 return field.IsInitOnly || field.IsLiteral;
392 public bool IsCallable(IType type)
394 return (TypeType == type) || IsCallableType(type) || IsDuckType(type);
397 public virtual bool IsDuckTyped(Expression expression)
399 IType type = expression.ExpressionType;
400 return null != type && this.IsDuckType(type);
403 public bool IsQuackBuiltin(Expression node)
405 return IsQuackBuiltin(GetOptionalEntity(node));
408 public bool IsQuackBuiltin(IEntity entity)
410 return BuiltinFunction.Quack == entity;
413 public bool IsDuckType(IType type)
415 if (null == type)
417 throw new ArgumentNullException("type");
419 return (
420 (type == DuckType)
421 || KnowsQuackFu(type)
422 || (_context.Parameters.Ducky
423 && (type == ObjectType)));
426 public bool KnowsQuackFu(IType type)
428 return type.IsSubclassOf(IQuackFuType);
431 bool IsCallableType(IType type)
433 return (ICallableType.IsAssignableFrom(type)) || (type is ICallableType);
436 public AnonymousCallableType GetCallableType(IMethod method)
438 CallableSignature signature = new CallableSignature(method);
439 return GetCallableType(signature);
442 public AnonymousCallableType GetCallableType(CallableSignature signature)
444 return _anonymousCallablesManager.GetCallableType(signature);
447 public virtual IType GetConcreteCallableType(Node sourceNode, CallableSignature signature)
449 return _anonymousCallablesManager.GetConcreteCallableType(sourceNode, signature);
452 public virtual IType GetConcreteCallableType(Node sourceNode, AnonymousCallableType anonymousType)
454 return _anonymousCallablesManager.GetConcreteCallableType(sourceNode, anonymousType);
457 public IType GetEnumeratorItemType(IType iteratorType)
459 // Arrays are enumerators of their element type
460 if (iteratorType.IsArray) return iteratorType.GetElementType();
462 // String are enumerators of char
463 if (StringType == iteratorType) return CharType;
465 // Try to use an EnumerableItemType attribute
466 if (iteratorType.IsClass)
468 IType enumeratorItemType = GetEnumeratorItemTypeFromAttribute(iteratorType);
469 if (null != enumeratorItemType) return enumeratorItemType;
472 // Try to use a generic IEnumerable interface
473 IType genericItemType = GetGenericEnumerableItemType(iteratorType);
474 if (null != genericItemType) return genericItemType;
476 // If none of these work, the type is an enumerator of object
477 return ObjectType;
480 public IType GetExpressionType(Expression node)
482 IType type = node.ExpressionType;
483 if (null == type)
485 throw CompilerErrorFactory.InvalidNode(node);
487 return type;
490 public IType GetConcreteExpressionType(Expression expression)
492 IType type = GetExpressionType(expression);
493 AnonymousCallableType anonymousType = type as AnonymousCallableType;
494 if (null != anonymousType)
496 IType concreteType = GetConcreteCallableType(expression, anonymousType);
497 expression.ExpressionType = concreteType;
498 return concreteType;
500 return type;
503 public void MapToConcreteExpressionTypes(ExpressionCollection items)
505 foreach (Expression item in items)
507 GetConcreteExpressionType(item);
511 public ClassDefinition GetCompilerGeneratedExtensionsClass()
513 if (null == _compilerGeneratedExtensionsClass)
515 BooClassBuilder builder = CodeBuilder.CreateClass("CompilerGeneratedExtensions");
516 builder.Modifiers = TypeMemberModifiers.Final|TypeMemberModifiers.Transient|TypeMemberModifiers.Public;
517 builder.AddBaseType(ObjectType);
519 BooMethodBuilder ctor = builder.AddConstructor();
520 ctor.Modifiers = TypeMemberModifiers.Private;
521 ctor.Body.Add(
522 CodeBuilder.CreateSuperConstructorInvocation(ObjectType));
524 ClassDefinition cd = builder.ClassDefinition;
525 Module module = GetCompilerGeneratedExtensionsModule();
526 module.Members.Add(cd);
527 ((ModuleEntity)module.Entity).InitializeModuleClass(cd);
529 _compilerGeneratedExtensionsClass = cd;
531 return _compilerGeneratedExtensionsClass;
534 public Module GetCompilerGeneratedExtensionsModule()
536 if (null == _compilerGeneratedExtensionsModule)
538 _compilerGeneratedExtensionsModule = NewModule(null, "CompilerGeneratedExtensions");
540 return _compilerGeneratedExtensionsModule;
543 public void AddCompilerGeneratedType(TypeDefinition type)
545 GetCompilerGeneratedTypesModule().Members.Add(type);
548 public Module GetCompilerGeneratedTypesModule()
550 if (null == _compilerGeneratedTypesModule)
552 _compilerGeneratedTypesModule = NewModule("CompilerGenerated");
554 return _compilerGeneratedTypesModule;
557 private Module NewModule(string nameSpace)
559 return NewModule(nameSpace, nameSpace);
562 private Module NewModule(string nameSpace, string moduleName)
564 Module module = new Module();
565 module.Name = moduleName;
566 if (null != nameSpace) module.Namespace = new NamespaceDeclaration(nameSpace);
567 module.Entity = new ModuleEntity(_context.NameResolutionService, this, module);
568 _context.CompileUnit.Modules.Add(module);
569 return module;
572 public ClassDefinition CreateCallableDefinition(string name)
574 ClassDefinition cd = new ClassDefinition();
575 cd.IsSynthetic = true;
576 cd.BaseTypes.Add(CodeBuilder.CreateTypeReference(this.MulticastDelegateType));
577 cd.BaseTypes.Add(CodeBuilder.CreateTypeReference(this.ICallableType));
578 cd.Name = name;
579 cd.Modifiers = TypeMemberModifiers.Final;
580 cd.Members.Add(CreateCallableConstructor());
581 cd.Members.Add(CreateCallMethod());
582 cd.Entity = new InternalCallableType(this, cd);
583 return cd;
586 Method CreateCallMethod()
588 Method method = new Method("Call");
589 method.IsSynthetic = true;
590 method.Modifiers = TypeMemberModifiers.Public|TypeMemberModifiers.Virtual;
591 method.Parameters.Add(CodeBuilder.CreateParameterDeclaration(1, "args", ObjectArrayType));
592 method.ReturnType = CodeBuilder.CreateTypeReference(ObjectType);
593 method.Entity = new InternalMethod(this, method);
594 return method;
597 Constructor CreateCallableConstructor()
599 Constructor constructor = new Constructor();
600 constructor.IsSynthetic = true;
601 constructor.Modifiers = TypeMemberModifiers.Public;
602 constructor.ImplementationFlags = MethodImplementationFlags.Runtime;
603 constructor.Parameters.Add(
604 CodeBuilder.CreateParameterDeclaration(1, "instance", ObjectType));
605 constructor.Parameters.Add(
606 CodeBuilder.CreateParameterDeclaration(2, "method", IntPtrType));
607 constructor.Entity = new InternalConstructor(this, constructor);
608 return constructor;
611 public bool AreTypesRelated(IType lhs, IType rhs)
613 ICallableType ctype = lhs as ICallableType;
614 if (null != ctype)
616 return ctype.IsAssignableFrom(rhs)
617 || ctype.IsSubclassOf(rhs);
620 return lhs.IsAssignableFrom(rhs)
621 || (lhs.IsInterface && !rhs.IsFinal)
622 || (rhs.IsInterface && !lhs.IsFinal)
623 || CanBeReachedByDownCastOrPromotion(lhs, rhs)
624 || FindImplicitConversionOperator(rhs,lhs) != null;
627 public IMethod FindExplicitConversionOperator(IType fromType, IType toType)
629 return FindConversionOperator("op_Explicit", fromType, toType);
632 public IMethod FindImplicitConversionOperator(IType fromType, IType toType)
634 return FindConversionOperator("op_Implicit", fromType, toType);
637 public IMethod FindConversionOperator(string name, IType fromType, IType toType)
639 while (fromType != this.ObjectType)
641 IMethod method = FindConversionOperator(name, fromType, toType, fromType.GetMembers());
642 if (null != method) return method;
643 method = FindConversionOperator(name, fromType, toType, toType.GetMembers());
644 if (null != method) return method;
645 method = FindConversionOperator(name, fromType, toType, FindExtension(fromType, name));
646 if (null != method) return method;
648 fromType = fromType.BaseType;
649 if (null == fromType) break;
651 return null;
654 private IEntity[] FindExtension(IType fromType, string name)
656 IEntity extension = _context.NameResolutionService.ResolveExtension(fromType, name);
657 if (null == extension) return Ambiguous.NoEntities;
659 Ambiguous a = extension as Ambiguous;
660 if (null != a) return a.Entities;
661 return new IEntity[] { extension };
664 IMethod FindConversionOperator(string name, IType fromType, IType toType, IEntity[] candidates)
666 foreach (IEntity entity in candidates)
668 if (EntityType.Method != entity.EntityType || name != entity.Name) continue;
669 IMethod method = (IMethod)entity;
670 if (IsConversionOperator(method, fromType, toType)) return method;
672 return null;
675 bool IsConversionOperator(IMethod method, IType fromType, IType toType)
677 if (!method.IsStatic) return false;
678 if (method.ReturnType != toType) return false;
679 IParameter[] parameters = method.GetParameters();
680 return (1 == parameters.Length && fromType == parameters[0].Type);
683 public bool IsCallableTypeAssignableFrom(ICallableType lhs, IType rhs)
685 if (lhs == rhs) return true;
686 if (Null.Default == rhs) return true;
688 ICallableType other = rhs as ICallableType;
689 if (null == other) return false;
691 CallableSignature lvalue = lhs.GetSignature();
692 CallableSignature rvalue = other.GetSignature();
693 if (lvalue == rvalue) return true;
695 IParameter[] lparams = lvalue.Parameters;
696 IParameter[] rparams = rvalue.Parameters;
697 if (lparams.Length < rparams.Length) return false;
699 for (int i=0; i<rparams.Length; ++i)
701 if (!AreTypesRelated(lparams[i].Type, rparams[i].Type)) return false;
704 return CompatibleReturnTypes(lvalue, rvalue);
707 private bool CompatibleReturnTypes(CallableSignature lvalue, CallableSignature rvalue)
709 if (VoidType != lvalue.ReturnType && VoidType != rvalue.ReturnType)
711 return AreTypesRelated(lvalue.ReturnType, rvalue.ReturnType);
714 return true;
717 public static bool CheckOverrideSignature(IMethod impl, IMethod baseMethod)
719 return CheckOverrideSignature(impl.GetParameters(), baseMethod.GetParameters());
722 public static bool CheckOverrideSignature(IParameter[] implParameters, IParameter[] baseParameters)
724 if (implParameters.Length != baseParameters.Length) return false;
726 for (int i=0; i<implParameters.Length; ++i)
728 IParameter implParameter = implParameters[i];
729 IParameter baseParameter = baseParameters[i];
730 IType implType = implParameter.Type;
731 IType baseType = baseParameter.Type;
733 if (baseType.IsByRef)
735 if (!implParameter.IsByRef) return false;
736 if (baseType.GetElementType() != implType) return false;
738 else
740 if (implType != baseType) return false;
743 return true;
746 public virtual bool CanBeReachedByDownCastOrPromotion(IType expectedType, IType actualType)
748 return CanBeReachedByDowncast(expectedType, actualType)
749 || CanBeReachedByPromotion(expectedType, actualType);
752 public virtual bool CanBeReachedByDowncast(IType expectedType, IType actualType)
754 return actualType.IsAssignableFrom(expectedType);
757 public virtual bool CanBeReachedByPromotion(IType expectedType, IType actualType)
759 return (expectedType.IsValueType
760 && IsNumber(expectedType)
761 && IsNumber(actualType));
764 public bool CanBeExplicitlyCastToInteger(IType type)
766 return type.IsEnum || type == this.CharType;
769 public static bool ContainsMethodsOnly(List members)
771 foreach (IEntity member in members)
773 if (EntityType.Method != member.EntityType) return false;
775 return true;
778 public bool IsIntegerNumber(IType type)
780 return
781 type == this.ShortType ||
782 type == this.IntType ||
783 type == this.LongType ||
784 type == this.SByteType ||
785 type == this.UShortType ||
786 type == this.UIntType ||
787 type == this.ULongType ||
788 type == this.ByteType;
791 public bool IsIntegerOrBool(IType type)
793 return BoolType == type || IsIntegerNumber(type);
796 public bool IsNumberOrBool(IType type)
798 return BoolType == type || IsNumber(type);
801 public bool IsNumber(IType type)
803 return
804 IsPrimitiveNumber(type) ||
805 type == this.DecimalType;
808 public bool IsPrimitiveNumber(IType type)
810 return
811 IsIntegerNumber(type) ||
812 type == this.DoubleType ||
813 type == this.SingleType;
816 public static bool IsUnknown(Expression node)
818 IType type = node.ExpressionType;
819 if (null != type)
821 return IsUnknown(type);
823 return false;
826 public static bool IsUnknown(IType tag)
828 return EntityType.Unknown == tag.EntityType;
831 public static bool IsError(Expression node)
833 IType type = node.ExpressionType;
834 if (null != type)
836 return IsError(type);
838 return false;
841 public static bool IsErrorAny(ExpressionCollection collection)
843 foreach (Expression n in collection)
845 if (IsError(n))
847 return true;
850 return false;
853 public bool IsBuiltin(IEntity tag)
855 if (EntityType.Method == tag.EntityType)
857 return BuiltinsType == ((IMethod)tag).DeclaringType;
859 return false;
862 public static bool IsError(IEntity tag)
864 return EntityType.Error == tag.EntityType;
867 public static TypeMemberModifiers GetAccess(IAccessibleMember member)
869 if (member.IsPublic)
871 return TypeMemberModifiers.Public;
873 else if (member.IsProtected)
875 return TypeMemberModifiers.Protected;
877 return TypeMemberModifiers.Private;
880 public static IEntity[] GetAllMembers(INamespace entity)
882 List members = new List();
883 GetAllMembers(members, entity);
884 return (IEntity[])members.ToArray(new IEntity[members.Count]);
887 private static void GetAllMembers(List members, INamespace entity)
889 if (null == entity) return;
891 IType type = entity as IType;
892 if (null != type)
894 members.ExtendUnique(type.GetMembers());
895 GetAllMembers(members, type.BaseType);
897 else
899 members.Extend(entity.GetMembers());
903 static object EntityAnnotationKey = new object();
905 public static void Bind(Node node, IEntity entity)
907 if (null == node) throw new ArgumentNullException("node");
908 node[EntityAnnotationKey] = entity;
911 public static IEntity GetOptionalEntity(Node node)
913 if (null == node) throw new ArgumentNullException("node");
914 return (IEntity)node[EntityAnnotationKey];
917 public static IEntity GetEntity(Node node)
919 IEntity tag = GetOptionalEntity(node);
920 if (null == tag) InvalidNode(node);
922 return tag;
925 public static IType GetReferencedType(Expression typeref)
927 switch (typeref.NodeType)
929 case NodeType.TypeofExpression:
931 return GetType(((TypeofExpression)typeref).Type);
933 case NodeType.ReferenceExpression:
934 case NodeType.MemberReferenceExpression:
935 case NodeType.GenericReferenceExpression:
937 return typeref.Entity as IType;
940 return null;
943 public virtual bool IsModule(Type type)
945 return type.IsClass
946 && type.IsSealed
947 && !type.IsNestedPublic
948 && MetadataUtil.IsAttributeDefined(type, Types.ModuleAttribute);
951 public bool IsAttribute(IType type)
953 return type.IsSubclassOf(SystemAttribute);
956 public static IType GetType(Node node)
958 return ((ITypedEntity)GetEntity(node)).Type;
961 public IType Map(Type type)
963 ExternalType entity = (ExternalType)_entityCache[type];
964 if (null == entity)
966 if (type.IsArray) return GetArrayType(Map(type.GetElementType()), type.GetArrayRank());
967 entity = CreateEntityForType(type);
968 Cache(entity);
970 return entity;
973 private ExternalType CreateEntityForType(Type type)
975 if (type.IsGenericParameter) return new ExternalGenericParameter(this, type);
976 if (type.IsSubclassOf(Types.MulticastDelegate)) return new ExternalCallableType(this, type);
977 return new ExternalType(this, type);
980 public IArrayType GetArrayType(IType elementType, int rank)
982 ArrayHash key = new ArrayHash(elementType, rank);
983 IArrayType entity = (IArrayType)_arrayCache[key];
984 if (null == entity)
986 entity = new ArrayType(this, elementType, rank);
987 _arrayCache.Add(key, entity);
989 return entity;
992 protected class ArrayHash
994 IType _type;
995 int _rank;
997 public ArrayHash(IType elementType, int rank)
999 _type = elementType;
1000 _rank = rank;
1003 public override int GetHashCode()
1005 return _type.GetHashCode() ^ _rank;
1008 public override bool Equals(object obj)
1010 return ((ArrayHash)obj)._type == _type && ((ArrayHash)obj)._rank == _rank;
1014 public IParameter[] Map(ParameterDeclarationCollection parameters)
1016 IParameter[] mapped = new IParameter[parameters.Count];
1017 for (int i=0; i<mapped.Length; ++i)
1019 mapped[i] = (IParameter)GetEntity(parameters[i]);
1021 return mapped;
1024 public IParameter[] Map(ParameterInfo[] parameters)
1026 IParameter[] mapped = new IParameter[parameters.Length];
1027 for (int i=0; i<parameters.Length; ++i)
1029 mapped[i] = new ExternalParameter(this, parameters[i]);
1031 return mapped;
1034 public IConstructor Map(ConstructorInfo constructor)
1036 object key = GetCacheKey(constructor);
1037 IConstructor entity = (IConstructor)_entityCache[key];
1038 if (null == entity)
1040 entity = new ExternalConstructor(this, constructor);
1041 _entityCache[key] = entity;
1043 return entity;
1046 public IMethod Map(MethodInfo method)
1048 object key = GetCacheKey(method);
1049 IMethod entity = (IMethod)_entityCache[key];
1050 if (null == entity)
1052 entity = new ExternalMethod(this, method);
1053 _entityCache[key] = entity;
1055 return entity;
1058 public IEntity Map(MemberInfo[] info)
1060 if (info.Length > 1)
1062 IEntity[] tags = new IEntity[info.Length];
1063 for (int i=0; i<tags.Length; ++i)
1065 tags[i] = Map(info[i]);
1067 return new Ambiguous(tags);
1069 if (info.Length > 0)
1071 return Map(info[0]);
1073 return null;
1076 public IEntity Map(MemberInfo mi)
1078 IEntity tag = (IEntity)_entityCache[GetCacheKey(mi)];
1079 if (null == tag)
1081 switch (mi.MemberType)
1083 case MemberTypes.Method:
1085 return Map((MethodInfo)mi);
1088 case MemberTypes.Constructor:
1090 return Map((ConstructorInfo)mi);
1093 case MemberTypes.Field:
1095 tag = new ExternalField(this, (FieldInfo)mi);
1096 break;
1099 case MemberTypes.Property:
1101 tag = new ExternalProperty(this, (PropertyInfo)mi);
1102 break;
1105 case MemberTypes.Event:
1107 tag = new ExternalEvent(this, (EventInfo)mi);
1108 break;
1111 case MemberTypes.NestedType:
1113 return Map((Type)mi);
1116 default:
1118 throw new NotImplementedException(mi.ToString());
1121 _entityCache.Add(GetCacheKey(mi), tag);
1123 return tag;
1126 public string GetSignature(IEntityWithParameters method)
1128 return GetSignature(method, true);
1131 public string GetSignature(IEntityWithParameters method, bool includeFullName)
1133 _buffer.Length = 0;
1134 if (includeFullName)
1136 _buffer.Append(method.FullName);
1138 else
1140 _buffer.Append(method.Name);
1142 _buffer.Append("(");
1144 IParameter[] parameters = method.GetParameters();
1145 for (int i=0; i<parameters.Length; ++i)
1147 if (i > 0) { _buffer.Append(", "); }
1148 if (method.AcceptVarArgs && i == parameters.Length-1) { _buffer.Append('*'); }
1149 _buffer.Append(parameters[i].Type);
1151 _buffer.Append(")");
1152 return _buffer.ToString();
1155 public object GetCacheKey(MemberInfo mi)
1157 return mi;
1160 public IEntity ResolvePrimitive(string name)
1162 return (IEntity)_primitives[name];
1165 public bool IsPrimitive(string name)
1167 return _primitives.ContainsKey(name);
1170 /// <summary>
1171 /// checks if the passed type will be equivalente to
1172 /// System.Object in runtime (accounting for the presence
1173 /// of duck typing).
1174 /// </summary>
1175 public bool IsSystemObject(IType type)
1177 return type == ObjectType || type == DuckType;
1180 public bool RequiresBoxing(IType expectedType, IType actualType)
1182 if (!actualType.IsValueType) return false;
1183 return IsSystemObject(expectedType);
1186 protected virtual void PreparePrimitives()
1188 AddPrimitiveType("duck", DuckType);
1189 AddPrimitiveType("void", VoidType);
1190 AddPrimitiveType("object", ObjectType);
1191 AddPrimitiveType("bool", BoolType);
1192 AddPrimitiveType("sbyte", SByteType);
1193 AddPrimitiveType("byte", ByteType);
1194 AddPrimitiveType("short", ShortType);
1195 AddPrimitiveType("ushort", UShortType);
1196 AddPrimitiveType("int", IntType);
1197 AddPrimitiveType("uint", UIntType);
1198 AddPrimitiveType("long", LongType);
1199 AddPrimitiveType("ulong", ULongType);
1200 AddPrimitiveType("single", SingleType);
1201 AddPrimitiveType("double", DoubleType);
1202 AddPrimitiveType("decimal", DecimalType);
1203 AddPrimitiveType("char", CharType);
1204 AddPrimitiveType("string", StringType);
1205 AddPrimitiveType("regex", RegexType);
1206 AddPrimitiveType("date", DateTimeType);
1207 AddPrimitiveType("timespan", TimeSpanType);
1208 AddPrimitiveType("callable", ICallableType);
1211 protected virtual void PrepareBuiltinFunctions()
1213 AddBuiltin(BuiltinFunction.Len);
1214 AddBuiltin(BuiltinFunction.AddressOf);
1215 AddBuiltin(BuiltinFunction.Eval);
1216 AddBuiltin(BuiltinFunction.Switch);
1219 protected void AddPrimitiveType(string name, ExternalType type)
1221 _primitives[name] = type;
1222 type.PrimitiveName = name;
1225 protected void AddBuiltin(BuiltinFunction function)
1227 _primitives[function.Name] = function;
1230 void Cache(ExternalType tag)
1232 _entityCache[tag.ActualType] = tag;
1235 void Cache(object key, IType tag)
1237 _entityCache[key] = tag;
1240 public IConstructor GetDefaultConstructor(IType type)
1242 IConstructor[] constructors = type.GetConstructors();
1243 for (int i=0; i<constructors.Length; ++i)
1245 IConstructor constructor = constructors[i];
1246 if (0 == constructor.GetParameters().Length)
1248 return constructor;
1251 return null;
1254 IType GetExternalEnumeratorItemType(IType iteratorType)
1256 Type type = ((ExternalType)iteratorType).ActualType;
1257 EnumeratorItemTypeAttribute attribute = (EnumeratorItemTypeAttribute)System.Attribute.GetCustomAttribute(type, typeof(EnumeratorItemTypeAttribute));
1258 if (null != attribute)
1260 return Map(attribute.ItemType);
1262 return null;
1265 IType GetEnumeratorItemTypeFromAttribute(IType iteratorType)
1267 // If iterator type is external get its attributes via reflection
1268 if (iteratorType is ExternalType)
1270 return GetExternalEnumeratorItemType(iteratorType);
1273 // If iterator type is a generic constructed type, map its attribute from its definition
1274 GenericConstructedType constructedType = iteratorType as GenericConstructedType;
1275 if (constructedType != null)
1277 return constructedType.GenericMapping.Map(
1278 GetEnumeratorItemTypeFromAttribute(constructedType.GenericDefinition));
1281 // If iterator type is internal get its attributes from its type definition
1282 AbstractInternalType internalType = (AbstractInternalType)iteratorType;
1283 IType enumeratorItemTypeAttribute = Map(typeof(EnumeratorItemTypeAttribute));
1284 foreach (Attribute attribute in internalType.TypeDefinition.Attributes)
1286 IConstructor constructor = GetEntity(attribute) as IConstructor;
1287 if (null != constructor)
1289 if (constructor.DeclaringType == enumeratorItemTypeAttribute)
1291 return GetType(attribute.Arguments[0]);
1295 return null;
1298 public IType GetGenericEnumerableItemType(IType iteratorType)
1300 // Arrays implicitly implement IEnumerable[of element type]
1301 if (iteratorType is ArrayType) return iteratorType.GetElementType();
1303 // If type is not an array, try to find IEnumerable[of some type] in its interfaces
1304 IType itemType = null;
1305 foreach (IType type in GenericsServices.FindConstructedTypes(iteratorType, IEnumerableGenericType))
1307 IType candidateItemType = type.ConstructedInfo.GenericArguments[0];
1309 if (itemType != null)
1311 itemType = GetMostGenericType(itemType, candidateItemType);
1313 else
1315 itemType = candidateItemType;
1319 return itemType;
1322 public IEntity GetMemberEntity(TypeMember member)
1324 if (null == member.Entity)
1326 member.Entity = CreateEntity(member);
1328 return member.Entity;
1331 private IEntity CreateEntity(TypeMember member)
1333 switch (member.NodeType)
1335 case NodeType.ClassDefinition:
1336 return new InternalClass(this, (TypeDefinition) member);
1337 case NodeType.Field:
1338 return new InternalField((Field)member);
1339 case NodeType.EnumMember:
1340 return new InternalEnumMember(this, (EnumMember)member);
1341 case NodeType.Method:
1342 return new InternalMethod(this, (Method)member);
1343 case NodeType.Constructor:
1344 return new InternalConstructor(this, (Constructor)member);
1345 case NodeType.Property:
1346 return new InternalProperty(this, (Property)member);
1347 case NodeType.Event:
1348 return new InternalEvent(this, (Event)member);
1350 throw new ArgumentException("Member type not supported: " + member);
1354 private static void InvalidNode(Node node)
1356 throw CompilerErrorFactory.InvalidNode(node);
1359 public class DuckTypeImpl : ExternalType
1361 public DuckTypeImpl(TypeSystemServices typeSystemServices) :
1362 base(typeSystemServices, Types.Object)
1367 #region VoidTypeImpl
1368 class VoidTypeImpl : ExternalType
1370 internal VoidTypeImpl(TypeSystemServices typeSystemServices) : base(typeSystemServices, Types.Void)
1374 override public bool Resolve(List targetList, string name, EntityType flags)
1376 return false;
1379 override public bool IsSubclassOf(IType other)
1381 return false;
1384 override public bool IsAssignableFrom(IType other)
1386 return false;
1390 #endregion