public override IType VisitParameterizedType(ParameterizedTypeSpec type) { IType newType = base.VisitParameterizedType(type); if (newType != type && ConstraintsValid) { // something was changed, so we need to validate the constraints ParameterizedTypeSpec newParameterizedType = newType as ParameterizedTypeSpec; if (newParameterizedType != null) { // V# 4.0 spec: §4.4.4 Satisfying constraints var typeParameters = newParameterizedType.GetDefinition().TypeParameters; var substitution = newParameterizedType.GetSubstitution(); for (int i = 0; i < typeParameters.Count; i++) { if (!ValidateConstraints(typeParameters[i], newParameterizedType.GetTypeArgument(i), substitution, conversions)) { ConstraintsValid = false; break; } } } } return(newType); }
static int MoreSpecificFormalParameter(IType t1, IType t2) { if ((t1 is ITypeParameter) && !(t2 is ITypeParameter)) { return(2); } if ((t2 is ITypeParameter) && !(t1 is ITypeParameter)) { return(1); } ParameterizedTypeSpec p1 = t1 as ParameterizedTypeSpec; ParameterizedTypeSpec p2 = t2 as ParameterizedTypeSpec; if (p1 != null && p2 != null && p1.TypeParameterCount == p2.TypeParameterCount) { int r = MoreSpecificFormalParameters(p1.TypeArguments, p2.TypeArguments); if (r > 0) { return(r); } } ElementTypeSpec tew1 = t1 as ElementTypeSpec; ElementTypeSpec tew2 = t2 as ElementTypeSpec; if (tew1 != null && tew2 != null) { return(MoreSpecificFormalParameter(tew1.ElementType, tew2.ElementType)); } return(0); }
static IEnumerable <IType> GetNestedTypesImpl(IType outerType, IList <IType> nestedTypeArguments, Predicate <ITypeDefinition> filter, GetMemberOptions options) { ITypeDefinition outerTypeDef = outerType.GetDefinition(); if (outerTypeDef == null) { yield break; } int outerTypeParameterCount = outerTypeDef.TypeParameterCount; ParameterizedTypeSpec pt = outerType as ParameterizedTypeSpec; foreach (ITypeDefinition nestedType in outerTypeDef.NestedTypes) { int totalTypeParameterCount = nestedType.TypeParameterCount; if (nestedTypeArguments != null) { if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) { continue; } } if (!(filter == null || filter(nestedType))) { continue; } if (totalTypeParameterCount == 0 || (options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { yield return(nestedType); } else { // We need to parameterize the nested type IType[] newTypeArguments = new IType[totalTypeParameterCount]; for (int i = 0; i < outerTypeParameterCount; i++) { newTypeArguments[i] = pt != null?pt.GetTypeArgument(i) : outerTypeDef.TypeParameters[i]; } for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { if (nestedTypeArguments != null) { newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; } else { newTypeArguments[i] = SpecialTypeSpec.UnboundTypeArgument; } } yield return(new ParameterizedTypeSpec(nestedType, newTypeArguments)); } } }
static IMethod GetDelegateOrExpressionTreeSignature(IType t) { ParameterizedTypeSpec pt = t as ParameterizedTypeSpec; if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Expression" && pt.Namespace == "Std.Linq.Expressions") { t = pt.GetTypeArgument(0); } return(t.GetDelegateInvokeMethod()); }
Expression LookInUsingScopeNamespace(ResolveContext rc, ResolvedUsingScope usingScope, INamespace n, string identifier, IList <IType> typeArguments, bool parameterizeResultType) { if (n == null) { return(null); } // first look for a namespace int k = typeArguments.Count; if (k == 0) { INamespace childNamespace = n.GetChildNamespace(identifier); if (childNamespace != null) { if (usingScope != null && usingScope.HasAlias(identifier)) { rc.Report.Error(7, loc, "The name `{0}' is ambigious", name); return(new TypeExpression((IType) new UnknownTypeSpec(null, identifier), Location)); // ambigious } return(new AliasNamespace(childNamespace, Location)); } } // then look for a type ITypeDefinition def = n.GetTypeDefinition(identifier, k); if (def != null) { IType result = def; if (parameterizeResultType && k > 0) { result = new ParameterizedTypeSpec(def, typeArguments); } if (usingScope != null && usingScope.HasAlias(identifier)) { rc.Report.Error(7, loc, "The name `{0}' is ambigious", name); return(new TypeExpression((IType) new UnknownTypeSpec(null, identifier), Location)); // ambigious } else { return(new TypeExpression(result, Location)); } } return(null); }
static bool IsGenericInterfaceImplementedByArray(ParameterizedTypeSpec rt) { if (rt == null || rt.TypeParameterCount != 1) { return(false); } switch (rt.GetDefinition().KnownTypeCode) { case KnownTypeCode.IEnumerableOfT: case KnownTypeCode.ICollectionOfT: case KnownTypeCode.IListOfT: case KnownTypeCode.IReadOnlyCollectionOfT: case KnownTypeCode.IReadOnlyListOfT: return(true); default: return(false); } }
/// <summary> /// Make exact inference from U to V. /// V# 4.0 spec: §7.5.2.8 Exact inferences /// </summary> void MakeExactInference(IType U, IType V) { // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.IsFixed == false) { tp.AddExactBound(U); return; } // Handle by reference types: ByReferenceType brU = U as ByReferenceType; ByReferenceType brV = V as ByReferenceType; if (brU != null && brV != null) { MakeExactInference(brU.ElementType, brV.ElementType); return; } // Handle array types: ArrayType arrU = U as ArrayType; ArrayType arrV = V as ArrayType; if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions) { MakeExactInference(arrU.ElementType, arrV.ElementType); return; } // Handle parameterized type: ParameterizedTypeSpec pU = U as ParameterizedTypeSpec; ParameterizedTypeSpec pV = V as ParameterizedTypeSpec; if (pU != null && pV != null && object.Equals(pU.GetDefinition(), pV.GetDefinition()) && pU.TypeParameterCount == pV.TypeParameterCount) { for (int i = 0; i < pU.TypeParameterCount; i++) { MakeExactInference(pU.GetTypeArgument(i), pV.GetTypeArgument(i)); } } }
public void ResolveSelfType(ResolveContext rc) { eclass = ExprClass.Variable; if (!IsSelfOrSuperAvailable(rc, false)) { if (rc.IsStatic && !rc.HasSet(ResolveContext.Options.ConstantScope)) { rc.Report.Error(241, loc, "Keyword `self' is not valid in a static property, static method, or static field initializer"); } else if (rc.CurrentAnonymousMethod != null) { rc.Report.Error(242, loc, "Anonymous methods inside structs cannot access instance members of `self'. " + "Consider copying `self' to a local variable outside the anonymous method and using the local instead"); } else { rc.Report.Error(243, loc, "Keyword `self' is not available in the current context"); } return; } ITypeDefinition t = rc.CurrentTypeDefinition; if (t != null) { if (t.TypeParameterCount != 0) { // Self-parameterize the type ResolvedType = new ParameterizedTypeSpec(t, t.TypeParameters); } else { ResolvedType = t; } } _resolved = true; }
static IEnumerable <IMethod> GetMethodsImpl(IType baseType, IList <IType> methodTypeArguments, Predicate <IUnresolvedMethod> filter, GetMemberOptions options) { IEnumerable <IMethod> declaredMethods = baseType.GetMethods(filter, options | declaredMembers); ParameterizedTypeSpec pt = baseType as ParameterizedTypeSpec; if ((options & GetMemberOptions.ReturnMemberDefinitions) == 0 && (pt != null || (methodTypeArguments != null && methodTypeArguments.Count > 0))) { TypeParameterSubstitution substitution = null; foreach (IMethod m in declaredMethods) { if (methodTypeArguments != null && methodTypeArguments.Count > 0) { if (m.TypeParameters.Count != methodTypeArguments.Count) { continue; } } if (substitution == null) { if (pt != null) { substitution = pt.GetSubstitution(methodTypeArguments); } else { substitution = new TypeParameterSubstitution(null, methodTypeArguments); } } yield return(new SpecializedMethod(m, substitution)); } } else { foreach (IMethod m in declaredMethods) { yield return(m); } } }
static IEnumerable <IMethod> GetConstructorsOrAccessorsImpl(IType baseType, IEnumerable <IMethod> declaredMembers, Predicate <IUnresolvedMethod> filter, GetMemberOptions options) { if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { return(declaredMembers); } ParameterizedTypeSpec pt = baseType as ParameterizedTypeSpec; if (pt != null) { var substitution = pt.GetSubstitution(); return(declaredMembers.Select(m => new SpecializedMethod(m, substitution) { DeclaringType = pt })); } else { return(declaredMembers); } }
static IEnumerable <IEvent> GetEventsImpl(IType baseType, Predicate <IUnresolvedEvent> filter, GetMemberOptions options) { IEnumerable <IEvent> declaredEvents = baseType.GetEvents(filter, options | declaredMembers); if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { return(declaredEvents); } ParameterizedTypeSpec pt = baseType as ParameterizedTypeSpec; if (pt != null) { var substitution = pt.GetSubstitution(); return(declaredEvents.Select(m => new SpecializedEvent(m, substitution) { DeclaringType = pt })); } else { return(declaredEvents); } }
void RunTypeInference(Candidate candidate) { if (candidate.TypeParameters == null) { if (explicitlyGivenTypeArguments != null) { // method does not expect type arguments, but was given some candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments); } // Grab new parameter types: ResolveParameterTypes(candidate, true); return; } ParameterizedTypeSpec parameterizedDeclaringType = candidate.Member.DeclaringType as ParameterizedTypeSpec; IList <IType> classTypeArguments; if (parameterizedDeclaringType != null) { classTypeArguments = parameterizedDeclaringType.TypeArguments; } else { classTypeArguments = null; } // The method is generic: if (explicitlyGivenTypeArguments != null) { if (explicitlyGivenTypeArguments.Length == candidate.TypeParameters.Count) { candidate.InferredTypes = explicitlyGivenTypeArguments; } else { candidate.AddError(OverloadResolutionErrors.WrongNumberOfTypeArguments); // wrong number of type arguments given, so truncate the list or pad with UnknownType candidate.InferredTypes = new IType[candidate.TypeParameters.Count]; for (int i = 0; i < candidate.InferredTypes.Length; i++) { if (i < explicitlyGivenTypeArguments.Length) { candidate.InferredTypes[i] = explicitlyGivenTypeArguments[i]; } else { candidate.InferredTypes[i] = SpecialTypeSpec.UnknownType; } } } } else { TypeInference ti = new TypeInference(compilation, conversions); bool success; candidate.InferredTypes = ti.InferTypeArguments(candidate.TypeParameters, arguments, candidate.ParameterTypes, out success, classTypeArguments); if (!success) { candidate.AddError(OverloadResolutionErrors.TypeInferenceFailed); } } // Now substitute in the formal parameters: var substitution = new ConstraintValidatingSubstitution(classTypeArguments, candidate.InferredTypes, this); for (int i = 0; i < candidate.ParameterTypes.Length; i++) { candidate.ParameterTypes[i] = candidate.ParameterTypes[i].AcceptVisitor(substitution); } if (!substitution.ConstraintsValid) { candidate.AddError(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint); } }
Expression LookInCurrentUsingScope(ResolveContext rc, string identifier, IList <IType> typeArguments, bool isInUsingDeclaration, bool parameterizeResultType) { // look in current namespace definitions ResolvedUsingScope currentUsingScope = rc.CurrentUsingScope; for (ResolvedUsingScope u = currentUsingScope; u != null; u = u.Parent) { var resultInNamespace = LookInUsingScopeNamespace(rc, u, u.Namespace, identifier, typeArguments, parameterizeResultType); if (resultInNamespace != null) { return(resultInNamespace); } // then look for aliases: if (typeArguments.Count == 0) { if (u.ExternAliases.Contains(identifier)) { return(ResolveExternAlias(rc, identifier)); } if (!(isInUsingDeclaration && u == currentUsingScope)) { foreach (var pair in u.UsingAliases) { if (pair.Key == identifier) { return(pair.Value.ShallowClone()); } } } } // finally, look in the imported namespaces: if (!(isInUsingDeclaration && u == currentUsingScope)) { IType firstResult = null; foreach (var importedNamespace in u.Usings) { ITypeDefinition def = importedNamespace.GetTypeDefinition(identifier, typeArguments.Count); if (def != null) { IType resultType; if (parameterizeResultType && typeArguments.Count > 0) { resultType = new ParameterizedTypeSpec(def, typeArguments); } else { resultType = def; } if (firstResult == null || !TopLevelTypeDefinitionIsAccessible(rc, firstResult.GetDefinition())) { if (TopLevelTypeDefinitionIsAccessible(rc, resultType.GetDefinition())) { firstResult = resultType; } } else if (TopLevelTypeDefinitionIsAccessible(rc, def)) { rc.Report.Error(7, loc, "The name `{0}' is ambigious", name); return(new TypeExpression(firstResult, Location)); // ambigious } } } if (firstResult != null) { return(new TypeExpression(firstResult, Location)); } } // if we didn't find anything: repeat lookup with parent namespace } return(null); }
IList <IType> FindTypesInBounds(IList <IType> lowerBounds, IList <IType> upperBounds) { // If there's only a single type; return that single type. // If both inputs are empty, return the empty list. if (lowerBounds.Count == 0 && upperBounds.Count <= 1) { return(upperBounds); } if (upperBounds.Count == 0 && lowerBounds.Count <= 1) { return(lowerBounds); } if (nestingLevel > maxNestingLevel) { return(EmptyList <IType> .Instance); } // Finds a type X so that "LB <: X <: UB" // First try the Fixing algorithm from the V# spec (§7.5.2.11) List <IType> candidateTypes = lowerBounds.Union(upperBounds) .Where(c => lowerBounds.All(b => conversions.ImplicitConversion(b, c).IsValid)) .Where(c => upperBounds.All(b => conversions.ImplicitConversion(c, b).IsValid)) .ToList(); // evaluate the query only once // According to the V# specification, we need to pick the most specific // of the candidate types. (the type which has conversions to all others) // However, csc actually seems to choose the least specific. candidateTypes = candidateTypes.Where( c => candidateTypes.All(o => conversions.ImplicitConversion(o, c).IsValid) ).ToList(); // If the specified algorithm produces a single candidate, we return // that candidate. // We also return the whole candidate list if we're not using the improved // algorithm. if (candidateTypes.Count == 1 || !(algorithm == TypeInferenceAlgorithm.Improved || algorithm == TypeInferenceAlgorithm.ImprovedReturnAllResults)) { return(candidateTypes); } candidateTypes.Clear(); // Now try the improved algorithm List <ITypeDefinition> candidateTypeDefinitions; if (lowerBounds.Count > 0) { // Find candidates by using the lower bounds: var hashSet = new HashSet <ITypeDefinition>(lowerBounds[0].GetAllBaseTypeDefinitions()); for (int i = 1; i < lowerBounds.Count; i++) { hashSet.IntersectWith(lowerBounds[i].GetAllBaseTypeDefinitions()); } candidateTypeDefinitions = hashSet.ToList(); } else { // Find candidates by looking at all classes in the project: candidateTypeDefinitions = compilation.GetAllTypeDefinitions().ToList(); } // Now filter out candidates that violate the upper bounds: foreach (IType ub in upperBounds) { ITypeDefinition ubDef = ub.GetDefinition(); if (ubDef != null) { candidateTypeDefinitions.RemoveAll(c => !c.IsDerivedFrom(ubDef)); } } foreach (ITypeDefinition candidateDef in candidateTypeDefinitions) { // determine the type parameters for the candidate: IType candidate; if (candidateDef.TypeParameterCount == 0) { candidate = candidateDef; } else { bool success; IType[] result = InferTypeArgumentsFromBounds( candidateDef.TypeParameters, new ParameterizedTypeSpec(candidateDef, candidateDef.TypeParameters), lowerBounds, upperBounds, out success); if (success) { candidate = new ParameterizedTypeSpec(candidateDef, result); } else { continue; } } if (upperBounds.Count == 0) { // if there were only lower bounds, we aim for the most specific candidate: // if this candidate isn't made redundant by an existing, more specific candidate: if (!candidateTypes.Any(c => c.GetDefinition().IsDerivedFrom(candidateDef))) { // remove all existing candidates made redundant by this candidate: candidateTypes.RemoveAll(c => candidateDef.IsDerivedFrom(c.GetDefinition())); // add new candidate candidateTypes.Add(candidate); } } else { // if there were upper bounds, we aim for the least specific candidate: // if this candidate isn't made redundant by an existing, less specific candidate: if (!candidateTypes.Any(c => candidateDef.IsDerivedFrom(c.GetDefinition()))) { // remove all existing candidates made redundant by this candidate: candidateTypes.RemoveAll(c => c.GetDefinition().IsDerivedFrom(candidateDef)); // add new candidate candidateTypes.Add(candidate); } } } return(candidateTypes); }
/// <summary> /// Make upper bound inference from U to V. /// V# 4.0 spec: §7.5.2.10 Upper-bound inferences /// </summary> void MakeUpperBoundInference(IType U, IType V) { // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.IsFixed == false) { tp.UpperBounds.Add(U); return; } // Handle array types: ArrayType arrU = U as ArrayType; ArrayType arrV = V as ArrayType; ParameterizedTypeSpec pU = U as ParameterizedTypeSpec; if (arrV != null && arrU != null && arrU.Dimensions == arrV.Dimensions) { MakeUpperBoundInference(arrU.ElementType, arrV.ElementType); return; } else if (arrV != null && IsGenericInterfaceImplementedByArray(pU) && arrV.Dimensions == 1) { MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType); return; } // Handle parameterized types: if (pU != null) { ParameterizedTypeSpec uniqueBaseType = null; foreach (IType baseV in V.GetAllBaseTypes()) { ParameterizedTypeSpec pV = baseV as ParameterizedTypeSpec; if (pV != null && object.Equals(pU.GetDefinition(), pV.GetDefinition()) && pU.TypeParameterCount == pV.TypeParameterCount) { if (uniqueBaseType == null) { uniqueBaseType = pV; } else { return; // cannot make an inference because it's not unique } } } if (uniqueBaseType != null) { for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { IType Ui = pU.GetTypeArgument(i); IType Vi = uniqueBaseType.GetTypeArgument(i); if (Ui.IsReferenceType == true) { // look for variance ITypeParameter Xi = pU.GetDefinition().TypeParameters[i]; MakeExactInference(Ui, Vi); } else { // not known to be a reference type MakeExactInference(Ui, Vi); } } } } }