public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) { if (interningProvider == null) { interningProvider = InterningProvider.Dummy; } ITypeReference t = this.BaseType.ToTypeReference(lookupMode, interningProvider); if (this.HasNullableSpecifier) { t = interningProvider.Intern(NullableType.Create(t)); } int pointerRank = this.PointerRank; for (int i = 0; i < pointerRank; i++) { t = interningProvider.Intern(new PointerTypeReference(t)); } foreach (var a in this.ArraySpecifiers.Reverse()) { t = interningProvider.Intern(new ArrayTypeReference(t, a.Dimensions)); } if (this.HasRefSpecifier) { t = interningProvider.Intern(new ByReferenceTypeReference(t)); } return(t); }
bool ImplicitUserDefinedConversion(IType fromType, IType toType) { // C# 4.0 spec §6.4.4 User-defined implicit conversions // Currently we only test whether an applicable implicit conversion exists, // we do not resolve which conversion is the most specific and gets used. // Find the candidate operators: Predicate <IMethod> opImplicitFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1; var operators = NullableType.GetUnderlyingType(fromType).GetMethods(context, opImplicitFilter) .Concat(NullableType.GetUnderlyingType(toType).GetMethods(context, opImplicitFilter)); // Determine whether one of them is applicable: foreach (IMethod op in operators) { IType sourceType = op.Parameters[0].Type.Resolve(context); IType targetType = op.ReturnType.Resolve(context); // Try if the operator is applicable: if (StandardImplicitConversion(fromType, sourceType) && StandardImplicitConversion(targetType, toType)) { return(true); } // Try if the operator is applicable in lifted form: if (sourceType.IsReferenceType(context) == false && targetType.IsReferenceType(context) == false) { IType liftedSourceType = NullableType.Create(sourceType, context); IType liftedTargetType = NullableType.Create(targetType, context); if (StandardImplicitConversion(fromType, liftedSourceType) && StandardImplicitConversion(liftedTargetType, toType)) { return(true); } } } return(false); }
public override Expression DoResolve(ResolveContext rc) { if (_resolved) { return(this); } left = (FullNamedExpression)left.DoResolve(rc); IType t = left.Type; var nxt = spec; while (nxt != null) { if (nxt.IsNullable) { t = NullableType.Create(rc.Compilation, t); } else if (nxt.IsPointer) { t = new PointerTypeSpec(t); } else { t = new ArrayType(rc.Compilation, t, nxt.Dimension); } nxt = spec.Next; } ResolvedType = t; _resolved = true; return(this); }
public LiftedBinaryOperatorMethod(CSharpOperators operators, BinaryOperatorMethod baseMethod) : base(operators.compilation) { this.baseMethod = baseMethod; this.ReturnType = NullableType.Create(operators.compilation, baseMethod.ReturnType); this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[0])); this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[1])); }
IType MakeNullable(ResolveContext rc, IType type, bool isNullable) { if (isNullable) { return(NullableType.Create(rc.compilation, type)); } else { return(type); } }
void InitParameterArrays() { for (TypeCode i = TypeCode.Object; i <= TypeCode.String; i++) { normalParameters[i - TypeCode.Object] = new DefaultParameter(compilation.FindType(i), string.Empty); } for (TypeCode i = TypeCode.Boolean; i <= TypeCode.Decimal; i++) { IType type = NullableType.Create(compilation, compilation.FindType(i)); nullableParameters[i - TypeCode.Boolean] = new DefaultParameter(type, string.Empty); } }
public override ITypeReference ToTypeReference(NameLookupMode lookupMode = NameLookupMode.Type) { ITypeReference t = this.BaseType.ToTypeReference(lookupMode); if (this.HasNullableSpecifier) { t = NullableType.Create(t); } int pointerRank = this.PointerRank; for (int i = 0; i < pointerRank; i++) { t = new PointerTypeReference(t); } foreach (var a in this.ArraySpecifiers.Reverse()) { t = new ArrayTypeReference(t, a.Dimensions); } return(t); }
/// <summary> /// Infers the C# type for an IL instruction. /// /// Returns SpecialType.UnknownType for unsupported instructions. /// </summary> public static IType InferType(this ILInstruction inst, ICompilation compilation) { switch (inst) { case NewObj newObj: return(newObj.Method.DeclaringType); case NewArr newArr: if (compilation != null) { return(new ArrayType(compilation, newArr.Type, newArr.Indices.Count)); } else { return(SpecialType.UnknownType); } case Call call: return(call.Method.ReturnType); case CallVirt callVirt: return(callVirt.Method.ReturnType); case CallIndirect calli: return(calli.ReturnType); case UserDefinedLogicOperator logicOp: return(logicOp.Method.ReturnType); case LdObj ldobj: return(ldobj.Type); case StObj stobj: return(stobj.Type); case LdLoc ldloc: return(ldloc.Variable.Type); case StLoc stloc: return(stloc.Variable.Type); case LdLoca ldloca: return(new ByReferenceType(ldloca.Variable.Type)); case LdFlda ldflda: return(new ByReferenceType(ldflda.Field.Type)); case LdsFlda ldsflda: return(new ByReferenceType(ldsflda.Field.Type)); case LdElema ldelema: if (ldelema.Array.InferType(compilation) is ArrayType arrayType) { if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type)) { return(new ByReferenceType(arrayType.ElementType)); } } return(new ByReferenceType(ldelema.Type)); case Comp comp: if (compilation == null) { return(SpecialType.UnknownType); } switch (comp.LiftingKind) { case ComparisonLiftingKind.None: case ComparisonLiftingKind.CSharp: return(compilation.FindType(KnownTypeCode.Boolean)); case ComparisonLiftingKind.ThreeValuedLogic: return(NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean))); default: return(SpecialType.UnknownType); } case BinaryNumericInstruction bni: if (bni.IsLifted) { return(SpecialType.UnknownType); } switch (bni.Operator) { case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: var left = bni.Left.InferType(compilation); var right = bni.Right.InferType(compilation); if (left.Equals(right) && (left.IsCSharpPrimitiveIntegerType() || left.IsKnownType(KnownTypeCode.Boolean))) { return(left); } else { return(SpecialType.UnknownType); } default: return(SpecialType.UnknownType); } default: return(SpecialType.UnknownType); } }
List <OperatorInfo> GetApplicableConversionOperators(IType fromType, IType toType, bool isExplicit) { // Find the candidate operators: Predicate <IUnresolvedMethod> opFilter; if (isExplicit) { opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Explicit" && m.Parameters.Count == 1; } else { opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1; } var operators = NullableType.GetUnderlyingType(fromType).GetMethods(opFilter) .Concat(NullableType.GetUnderlyingType(toType).GetMethods(opFilter)).Distinct(); // Determine whether one of them is applicable: List <OperatorInfo> result = new List <OperatorInfo>(); foreach (IMethod op in operators) { IType sourceType = op.Parameters[0].Type; IType targetType = op.ReturnType; // Try if the operator is applicable: bool isApplicable; if (isExplicit) { isApplicable = IsEncompassingOrEncompassedBy(fromType, sourceType) && IsEncompassingOrEncompassedBy(targetType, toType); } else { isApplicable = IsEncompassedBy(fromType, sourceType) && IsEncompassedBy(targetType, toType); } if (isApplicable) { result.Add(new OperatorInfo(op, sourceType, targetType, false)); } // Try if the operator is applicable in lifted form: if (NullableType.IsNonNullableValueType(sourceType) && NullableType.IsNonNullableValueType(targetType)) { IType liftedSourceType = NullableType.Create(compilation, sourceType); IType liftedTargetType = NullableType.Create(compilation, targetType); if (isExplicit) { isApplicable = IsEncompassingOrEncompassedBy(fromType, liftedSourceType) && IsEncompassingOrEncompassedBy(liftedTargetType, toType); } else { isApplicable = IsEncompassedBy(fromType, liftedSourceType) && IsEncompassedBy(liftedTargetType, toType); } if (isApplicable) { result.Add(new OperatorInfo(op, liftedSourceType, liftedTargetType, true)); } } } return(result); }
public void SkeetEvilOverloadResolution() { // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx // static void Foo<T>(T? ignored = default(T?)) where T : struct var m1 = MakeMethod(); m1.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T") { HasValueTypeConstraint = true }); m1.Parameters.Add(MakeOptionalParameter( NullableType.Create(m1.TypeParameters[0], context), "ignored" )); // class ClassConstraint<T> where T : class {} DefaultTypeDefinition classConstraint = new DefaultTypeDefinition(dummyClass, "ClassConstraint"); classConstraint.TypeParameters.Add(new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T") { HasReferenceTypeConstraint = true }); // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>)) // where T : class var m2 = MakeMethod(); m2.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T") { HasReferenceTypeConstraint = true }); m2.Parameters.Add(MakeOptionalParameter( new ParameterizedType(classConstraint, new[] { m2.TypeParameters[0] }), "ignored" )); // static void Foo<T>() var m3 = MakeMethod(); m3.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T")); // Call: Foo<int>(); OverloadResolution o; o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int).ToTypeReference().Resolve(context) }); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m1)); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2)); Assert.AreSame(m1, o.BestCandidate); // Call: Foo<string>(); o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(string).ToTypeReference().Resolve(context) }); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1)); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m2)); Assert.AreSame(m2, o.BestCandidate); // Call: Foo<int?>(); o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int?).ToTypeReference().Resolve(context) }); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1)); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2)); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m3)); Assert.AreSame(m3, o.BestCandidate); }
public void SkeetEvilOverloadResolution() { // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx // static void Foo<T>(T? ignored = default(T?)) where T : struct var m1 = MakeUnresolvedMethod(); m1.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T") { HasValueTypeConstraint = true }); m1.Parameters.Add(MakeOptionalParameter( NullableType.Create(new TypeParameterReference(EntityType.Method, 0)), "ignored" )); // class ClassConstraint<T> where T : class {} var classConstraint = new DefaultUnresolvedTypeDefinition(string.Empty, "ClassConstraint"); classConstraint.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.TypeDefinition, 0, "T") { HasReferenceTypeConstraint = true }); // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>)) // where T : class var m2 = MakeUnresolvedMethod(); m2.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T") { HasReferenceTypeConstraint = true }); m2.Parameters.Add(MakeOptionalParameter( new ParameterizedTypeReference(classConstraint, new[] { new TypeParameterReference(EntityType.Method, 0) }), "ignored" )); // static void Foo<T>() var m3 = MakeUnresolvedMethod(); m3.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T")); var context = new SimpleTypeResolveContext(compilation.MainAssembly); IMethod resolvedM1 = (IMethod)m1.CreateResolved(context); IMethod resolvedM2 = (IMethod)m2.CreateResolved(context); IMethod resolvedM3 = (IMethod)m3.CreateResolved(context); // Call: Foo<int>(); OverloadResolution o; o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int)) }); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM1)); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2)); Assert.AreSame(resolvedM1, o.BestCandidate); // Call: Foo<string>(); o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(string)) }); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1)); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM2)); Assert.AreSame(resolvedM2, o.BestCandidate); // Call: Foo<int?>(); o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int?)) }); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1)); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2)); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM3)); Assert.AreSame(resolvedM3, o.BestCandidate); }
internal static ITypeReference ConvertType(AstType type, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration) { SimpleType s = type as SimpleType; if (s != null) { List <ITypeReference> typeArguments = new List <ITypeReference>(); foreach (var ta in s.TypeArguments) { typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration)); } if (typeArguments.Count == 0 && parentMethodDefinition != null) { // SimpleTypeOrNamespaceReference doesn't support method type parameters, // so we directly handle them here. foreach (ITypeParameter tp in parentMethodDefinition.TypeParameters) { if (tp.Name == s.Identifier) { return(tp); } } } return(new SimpleTypeOrNamespaceReference(s.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration)); } PrimitiveType p = type as PrimitiveType; if (p != null) { switch (p.Keyword) { case "string": return(KnownTypeReference.String); case "int": return(KnownTypeReference.Int32); case "uint": return(KnownTypeReference.UInt32); case "object": return(KnownTypeReference.Object); case "bool": return(KnownTypeReference.Boolean); case "sbyte": return(KnownTypeReference.SByte); case "byte": return(KnownTypeReference.Byte); case "short": return(KnownTypeReference.Int16); case "ushort": return(KnownTypeReference.UInt16); case "long": return(KnownTypeReference.Int64); case "ulong": return(KnownTypeReference.UInt64); case "float": return(KnownTypeReference.Single); case "double": return(KnownTypeReference.Double); case "decimal": return(ReflectionHelper.ToTypeReference(TypeCode.Decimal)); case "char": return(KnownTypeReference.Char); case "void": return(KnownTypeReference.Void); default: return(SharedTypes.UnknownType); } } MemberType m = type as MemberType; if (m != null) { ITypeOrNamespaceReference t; if (m.IsDoubleColon) { SimpleType st = m.Target as SimpleType; if (st != null) { t = new AliasNamespaceReference(st.Identifier, parentUsingScope); } else { t = null; } } else { t = ConvertType(m.Target, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration) as ITypeOrNamespaceReference; } if (t == null) { return(SharedTypes.UnknownType); } List <ITypeReference> typeArguments = new List <ITypeReference>(); foreach (var ta in m.TypeArguments) { typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration)); } return(new MemberTypeOrNamespaceReference(t, m.MemberName, typeArguments, parentTypeDefinition, parentUsingScope)); } ComposedType c = type as ComposedType; if (c != null) { ITypeReference t = ConvertType(c.BaseType, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration); if (c.HasNullableSpecifier) { t = NullableType.Create(t); } for (int i = 0; i < c.PointerRank; i++) { t = PointerTypeReference.Create(t); } foreach (var a in c.ArraySpecifiers.Reverse()) { t = ArrayTypeReference.Create(t, a.Dimensions); } return(t); } Debug.WriteLine("Unknown node used as type: " + type); return(SharedTypes.UnknownType); }