private SubstitutedParameterSymbol(Symbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) : base(originalParameter) { Debug.Assert(originalParameter.IsDefinition); _containingSymbol = containingSymbol; _mapOrType = map; }
protected SynthesizedContainer(string name, int parameterCount, bool returnsVoid) { Debug.Assert(name != null); this.name = name; this.typeMap = TypeMap.Empty; this.typeParameters = CreateTypeParameters(parameterCount, returnsVoid); }
internal SynthesizedContainer(MethodSymbol topLevelMethod, string name, TypeKind typeKind) { this.typeKind = typeKind; this.containingSymbol = topLevelMethod.ContainingType; this.name = name; this.TypeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out this.typeParameters); }
protected SynthesizedContainer(string name, MethodSymbol topLevelMethod) { Debug.Assert(name != null); Debug.Assert(topLevelMethod != null); this.name = name; this.typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out this.typeParameters); }
protected SynthesizedContainer(string name, int parameterCount, bool returnsVoid) { Debug.Assert(name != null); _name = name; _typeMap = TypeMap.Empty; _typeParameters = CreateTypeParameters(parameterCount, returnsVoid); _constructedFromTypeParameters = default(ImmutableArray<TypeParameterSymbol>); }
internal SynthesizedContainer(NamedTypeSymbol containingType, string name, TypeKind typeKind) { this.typeKind = typeKind; this.containingSymbol = containingType; this.name = name; this.TypeMap = TypeMap.Empty; this.typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; }
internal SubstitutedTypeParameterSymbol(Symbol newContainer, TypeMap map, TypeParameterSymbol substitutedFrom) { _container = newContainer; // it is important that we don't use the map here in the constructor, as the map is still being filled // in by TypeMap.WithAlphaRename. Instead, we can use the map lazily when yielding the constraints. _map = map; _substitutedFrom = substitutedFrom; }
protected void AssignTypeMapAndTypeParameters(TypeMap typeMap, ImmutableArray<TypeParameterSymbol> typeParameters) { Debug.Assert(typeMap != null); Debug.Assert(this.TypeMap == null); Debug.Assert(!typeParameters.IsDefault); Debug.Assert(_typeParameters.IsDefault); this.TypeMap = typeMap; _typeParameters = typeParameters; }
internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap) { Debug.Assert(method.IsStatic); var otherOrdinal = this.ContainingSymbol.IsStatic ? this.Parameter.Ordinal : (this.Parameter.Ordinal + 1); var otherParameter = method.Parameters[otherOrdinal]; return new DisplayClassInstanceFromParameter(otherParameter); }
protected SynthesizedContainer(string name, ImmutableArray<TypeParameterSymbol> typeParameters, TypeMap typeMap) { Debug.Assert(name != null); Debug.Assert(!typeParameters.IsDefault); Debug.Assert(typeMap != null); Name = name; _typeParameters = typeParameters; TypeMap = typeMap; }
private ExpressionLambdaRewriter(TypeCompilationState compilationState, TypeMap typeMap, CSharpSyntaxNode node, DiagnosticBag diagnostics) { Bound = new SyntheticBoundNodeFactory(null, null, node, compilationState, diagnostics); Int32Type = Bound.SpecialType(SpecialType.System_Int32); ObjectType = Bound.SpecialType(SpecialType.System_Object); NullableType = Bound.SpecialType(SpecialType.System_Nullable_T); IEnumerableType = Bound.SpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); this.typeMap = typeMap; }
internal static LocalSymbol ToOtherMethod(this LocalSymbol local, MethodSymbol method, TypeMap typeMap) { var l = local as EELocalSymbolBase; if ((object)l != null) { return l.ToOtherMethod(method, typeMap); } var type = typeMap.SubstituteType(local.Type); return new EELocalSymbol(method, local.Locations, local.Name, -1, local.DeclarationKind, type.Type, local.RefKind, local.IsPinned, local.IsCompilerGenerated, local.CanScheduleToStack); }
private static ConsList<FieldSymbol> SubstituteFields(ConsList<FieldSymbol> fields, TypeMap typeMap) { if (!fields.Any()) { return ConsList<FieldSymbol>.Empty; } var head = SubstituteField(fields.Head, typeMap); var tail = SubstituteFields(fields.Tail, typeMap); return tail.Prepend(head); }
internal SubstitutedTypeParameterSymbol(Symbol newContainer, TypeMap map, TypeParameterSymbol substitutedFrom, int ordinal) { _container = newContainer; // it is important that we don't use the map here in the constructor, as the map is still being filled // in by TypeMap.WithAlphaRename. Instead, we can use the map lazily when yielding the constraints. _map = map; _substitutedFrom = substitutedFrom; _ordinal = ordinal; #if DEBUG_ALPHA _mySequence = _nextSequence++; #endif }
protected SynthesizedContainer(string name, MethodSymbol containingMethod) { Debug.Assert(name != null); _name = name; if (containingMethod == null) { _typeMap = TypeMap.Empty; _typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; } else { _typeMap = TypeMap.Empty.WithConcatAlphaRename(containingMethod, this, out _typeParameters, out _constructedFromTypeParameters); } }
protected SubstitutedNamedTypeSymbol(Symbol newContainer, TypeMap map, NamedTypeSymbol originalDefinition, NamedTypeSymbol constructedFrom = null, bool unbound = false) { Debug.Assert(originalDefinition.IsDefinition); _originalDefinition = originalDefinition; _newContainer = newContainer; _inputMap = map; _unbound = unbound; // if we're substituting to create a new unconstructed type as a member of a constructed type, // then we must alpha rename the type parameters. if ((object)constructedFrom != null) { Debug.Assert(ReferenceEquals(constructedFrom.ConstructedFrom, constructedFrom)); _lazyTypeParameters = constructedFrom.TypeParameters; _lazyMap = map; } }
protected SubstitutedMethodSymbol(NamedTypeSymbol containingSymbol, TypeMap map, MethodSymbol originalDefinition, MethodSymbol constructedFrom) { Debug.Assert(originalDefinition.IsDefinition); _containingType = containingSymbol; this.originalDefinition = originalDefinition; _inputMap = map; if ((object)constructedFrom != null) { _constructedFrom = constructedFrom; Debug.Assert(ReferenceEquals(constructedFrom.ConstructedFrom, constructedFrom)); _lazyTypeParameters = constructedFrom.TypeParameters; _lazyMap = map; } else { _constructedFrom = this; } }
/// <summary> /// Used for <see cref="SynthesizedDelegateSymbol"/> construction. /// </summary> protected SynthesizedContainer(NamespaceOrTypeSymbol containingSymbol, string name, int parameterCount, bool returnsVoid) { var typeParameters = new TypeParameterSymbol[parameterCount + (returnsVoid ? 0 : 1)]; for (int i = 0; i < parameterCount; i++) { typeParameters[i] = new AnonymousTypeManager.AnonymousTypeParameterSymbol(this, i, "T" + (i + 1)); } if (!returnsVoid) { typeParameters[parameterCount] = new AnonymousTypeManager.AnonymousTypeParameterSymbol(this, parameterCount, "TResult"); } this.containingSymbol = containingSymbol; this.name = name; this.TypeMap = TypeMap.Empty; this.typeParameters = typeParameters.AsImmutableOrNull(); }
public bool Equals(Symbol member1, Symbol member2) { if (ReferenceEquals(member1, member2)) { return(true); } if ((object)member1 == null || (object)member2 == null || member1.Kind != member2.Kind) { return(false); } bool sawInterfaceInName1 = false; bool sawInterfaceInName2 = false; if (_considerName) { string name1 = ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(member1.Name); string name2 = ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(member2.Name); sawInterfaceInName1 = name1 != member1.Name; sawInterfaceInName2 = name2 != member2.Name; if (name1 != name2) { return(false); } } // NB: up to, and including, this check, we have not actually forced the (type) parameters // to be expanded - we're only using the counts. int arity = member1.GetMemberArity(); if ((arity != member2.GetMemberArity()) || (member1.GetParameterCount() != member2.GetParameterCount())) { return(false); } TypeMap typeMap1 = GetTypeMap(member1); TypeMap typeMap2 = GetTypeMap(member2); if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _typeComparison)) { return(false); } if (member1.GetParameterCount() > 0 && !HaveSameParameterTypes(member1.GetParameters(), typeMap1, member2.GetParameters(), typeMap2, _considerRefKindDifferences, _typeComparison)) { return(false); } if (_considerCallingConvention) { if (GetCallingConvention(member1) != GetCallingConvention(member2)) { return(false); } } else { if (IsVarargMethod(member1) != IsVarargMethod(member2)) { return(false); } } if (_considerExplicitlyImplementedInterfaces) { if (sawInterfaceInName1 != sawInterfaceInName2) { return(false); } // The purpose of this check is to determine whether the interface parts of the member names agree, // but to do so using robust symbolic checks, rather than syntactic ones. Therefore, if neither member // name contains an interface name, this check is not relevant. // Phrased differently, the explicitly implemented interface is not part of the signature unless it's // part of the name. if (sawInterfaceInName1) { Debug.Assert(sawInterfaceInName2); // May avoid realizing interface members. if (member1.IsExplicitInterfaceImplementation() != member2.IsExplicitInterfaceImplementation()) { return(false); } // By comparing symbols, rather than syntax, we gain the flexibility of ignoring whitespace // and gracefully accepting multiple names for the same (or equivalent) types (e.g. "I<int>.M" // vs "I<System.Int32>.M"), but we lose the connection with the name. For example, in metadata, // a method name "I.M" could have nothing to do with "I" but explicitly implement interface "I2". // We will behave as if the method was really named "I2.M". Furthermore, in metadata, a method // can explicitly implement more than one interface method, in which case it doesn't really // make sense to pretend that all of them are part of the signature. var explicitInterfaceImplementations1 = member1.GetExplicitInterfaceImplementations(); var explicitInterfaceImplementations2 = member2.GetExplicitInterfaceImplementations(); if (!explicitInterfaceImplementations1.SetEquals(explicitInterfaceImplementations2, SymbolEqualityComparer.ConsiderEverything)) { return(false); } } } return(!_considerTypeConstraints || HaveSameConstraints(member1, typeMap1, member2, typeMap2)); }
public SubstitutedNestedErrorTypeSymbol(NamedTypeSymbol containingSymbol, ErrorTypeSymbol originalDefinition) : base(originalDefinition) { this.containingSymbol = containingSymbol; this.map = containingSymbol.TypeSubstitution.WithAlphaRename(originalDefinition, this, out this.typeParameters); }
internal ImmutableArray <TypeWithAnnotations> GetTypeParametersAsTypeArguments() { return(TypeMap.TypeParametersAsTypeSymbolsWithAnnotations(TypeParameters)); }
private static bool HaveSameConstraints(Symbol member1, TypeMap typeMap1, Symbol member2, TypeMap typeMap2) { Debug.Assert(member1.GetMemberArity() == member2.GetMemberArity()); int arity = member1.GetMemberArity(); if (arity == 0) { return(true); } var typeParameters1 = member1.GetMemberTypeParameters(); var typeParameters2 = member2.GetMemberTypeParameters(); return(HaveSameConstraints(typeParameters1, typeMap1, typeParameters2, typeMap2)); }
// @t-mawind This is a hack... protected SynthesizedContainer(string name, Func <SynthesizedContainer, ImmutableArray <TypeParameterSymbol> > typeParametersF, TypeMap typeMap) { Debug.Assert(name != null); Debug.Assert(typeParametersF != null); Debug.Assert(typeMap != null); _name = name; _typeParameters = typeParametersF(this); Debug.Assert(!_typeParameters.IsDefault); _typeMap = typeMap; }
private static MethodSymbol InferExtensionMethodTypeArguments(MethodSymbol method, TypeSymbol thisType, CSharpCompilation compilation, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo) { Debug.Assert(method.IsExtensionMethod); Debug.Assert((object)thisType != null); if (!method.IsGenericMethod || method != method.ConstructedFrom) { return(method); } // We never resolve extension methods on a dynamic receiver. if (thisType.IsDynamic()) { return(null); } var containingAssembly = method.ContainingAssembly; var errorNamespace = containingAssembly.GlobalNamespace; var conversions = new TypeConversions(containingAssembly.CorLibrary); // There is absolutely no plausible syntax/tree that we could use for these // synthesized literals. We could be speculatively binding a call to a PE method. var syntaxTree = CSharpSyntaxTree.Dummy; var syntax = (CSharpSyntaxNode)syntaxTree.GetRoot(); // Create an argument value for the "this" argument of specific type, // and pass the same bad argument value for all other arguments. var thisArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, thisType) { WasCompilerGenerated = true }; var otherArgumentType = new ExtendedErrorTypeSymbol(errorNamespace, name: string.Empty, arity: 0, errorInfo: null, unreported: false); var otherArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, otherArgumentType) { WasCompilerGenerated = true }; var paramCount = method.ParameterCount; var arguments = new BoundExpression[paramCount]; for (int i = 0; i < paramCount; i++) { var argument = (i == 0) ? thisArgumentValue : otherArgumentValue; arguments[i] = argument; } var typeArgs = MethodTypeInferrer.InferTypeArgumentsFromFirstArgument( conversions, method, arguments.AsImmutable(), useSiteInfo: ref useSiteInfo); if (typeArgs.IsDefault) { return(null); } // For the purpose of constraint checks we use error type symbol in place of type arguments that we couldn't infer from the first argument. // This prevents constraint checking from failing for corresponding type parameters. int firstNullInTypeArgs = -1; var notInferredTypeParameters = PooledHashSet <TypeParameterSymbol> .GetInstance(); var typeParams = method.TypeParameters; var typeArgsForConstraintsCheck = typeArgs; for (int i = 0; i < typeArgsForConstraintsCheck.Length; i++) { if (!typeArgsForConstraintsCheck[i].HasType) { firstNullInTypeArgs = i; var builder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); builder.AddRange(typeArgsForConstraintsCheck, firstNullInTypeArgs); for (; i < typeArgsForConstraintsCheck.Length; i++) { var typeArg = typeArgsForConstraintsCheck[i]; if (!typeArg.HasType) { notInferredTypeParameters.Add(typeParams[i]); builder.Add(TypeWithAnnotations.Create(ErrorTypeSymbol.UnknownResultType)); } else { builder.Add(typeArg); } } typeArgsForConstraintsCheck = builder.ToImmutableAndFree(); break; } } // Check constraints. var diagnosticsBuilder = ArrayBuilder <TypeParameterDiagnosticInfo> .GetInstance(); var substitution = new TypeMap(typeParams, typeArgsForConstraintsCheck); ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null; var success = method.CheckConstraints(new ConstraintsHelper.CheckConstraintsArgs(compilation, conversions, includeNullability: false, NoLocation.Singleton, diagnostics: null, template: new CompoundUseSiteInfo <AssemblySymbol>(useSiteInfo)), substitution, typeParams, typeArgsForConstraintsCheck, diagnosticsBuilder, nullabilityDiagnosticsBuilderOpt: null, ref useSiteDiagnosticsBuilder, ignoreTypeConstraintsDependentOnTypeParametersOpt: notInferredTypeParameters.Count > 0 ? notInferredTypeParameters : null); diagnosticsBuilder.Free(); notInferredTypeParameters.Free(); if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0) { foreach (var diag in useSiteDiagnosticsBuilder) { useSiteInfo.Add(diag.UseSiteInfo); } } if (!success) { return(null); } // For the purpose of construction we use original type parameters in place of type arguments that we couldn't infer from the first argument. ImmutableArray <TypeWithAnnotations> typeArgsForConstruct = typeArgs; if (typeArgs.Any(t => !t.HasType)) { typeArgsForConstruct = typeArgs.ZipAsArray( method.TypeParameters, (t, tp) => t.HasType ? t : TypeWithAnnotations.Create(tp)); } return(method.Construct(typeArgsForConstruct)); }
private FieldSymbol VisitFieldSymbol(FieldSymbol field) { // Property of a regular type return(((FieldSymbol)field.OriginalDefinition) .AsMember((NamedTypeSymbol)TypeMap.SubstituteType(field.ContainingType).AsTypeSymbolOnly())); }
private static void SubstituteConstraintTypes(ImmutableArray <TypeWithAnnotations> types, TypeMap typeMap, HashSet <TypeSymbol> result) { foreach (var type in types) { result.Add(typeMap.SubstituteType(type).Type); } }
public static bool HaveSameNullabilityInConstraints(TypeParameterSymbol typeParameter1, TypeMap typeMap1, TypeParameterSymbol typeParameter2, TypeMap typeMap2) { if (!typeParameter1.IsValueType) { bool?isNotNullable1 = typeParameter1.IsNotNullable; bool?isNotNullable2 = typeParameter2.IsNotNullable; if (isNotNullable1.HasValue && isNotNullable2.HasValue && isNotNullable1.GetValueOrDefault() != isNotNullable2.GetValueOrDefault()) { return(false); } } return(HaveSameTypeConstraints(typeParameter1, typeMap1, typeParameter2, typeMap2, SymbolEqualityComparer.AllIgnoreOptionsPlusNullableWithUnknownMatchesAny)); }
private static bool HaveSameTypeConstraints(TypeParameterSymbol typeParameter1, TypeMap typeMap1, TypeParameterSymbol typeParameter2, TypeMap typeMap2, IEqualityComparer <TypeSymbol> comparer) { // Check that constraintTypes1 is a subset of constraintTypes2 and // also that constraintTypes2 is a subset of constraintTypes1 // (see SymbolPreparer::CheckImplicitImplConstraints). var constraintTypes1 = typeParameter1.ConstraintTypesNoUseSiteDiagnostics; var constraintTypes2 = typeParameter2.ConstraintTypesNoUseSiteDiagnostics; // The two sets of constraints may differ in size but still be considered // the same (duplicated constraints, ignored "object" constraints), but // if both are zero size, the sets must be equal. if ((constraintTypes1.Length == 0) && (constraintTypes2.Length == 0)) { return(true); } var substitutedTypes1 = new HashSet <TypeSymbol>(comparer); var substitutedTypes2 = new HashSet <TypeSymbol>(comparer); SubstituteConstraintTypes(constraintTypes1, typeMap1, substitutedTypes1); SubstituteConstraintTypes(constraintTypes2, typeMap2, substitutedTypes2); return(AreConstraintTypesSubset(substitutedTypes1, substitutedTypes2, typeParameter2) && AreConstraintTypesSubset(substitutedTypes2, substitutedTypes1, typeParameter1)); }
public static bool HaveSameConstraints(TypeParameterSymbol typeParameter1, TypeMap typeMap1, TypeParameterSymbol typeParameter2, TypeMap typeMap2) { // Spec 13.4.3: Implementation of generic methods. if ((typeParameter1.HasConstructorConstraint != typeParameter2.HasConstructorConstraint) || (typeParameter1.HasReferenceTypeConstraint != typeParameter2.HasReferenceTypeConstraint) || (typeParameter1.HasValueTypeConstraint != typeParameter2.HasValueTypeConstraint) || (typeParameter1.HasUnmanagedTypeConstraint != typeParameter2.HasUnmanagedTypeConstraint) || (typeParameter1.Variance != typeParameter2.Variance)) { return(false); } return(HaveSameTypeConstraints(typeParameter1, typeMap1, typeParameter2, typeMap2, SymbolEqualityComparer.IgnoringDynamicTupleNamesAndNullability)); }
public static bool HaveSameConstraints(ImmutableArray <TypeParameterSymbol> typeParameters1, TypeMap typeMap1, ImmutableArray <TypeParameterSymbol> typeParameters2, TypeMap typeMap2) { Debug.Assert(typeParameters1.Length == typeParameters2.Length); int arity = typeParameters1.Length; for (int i = 0; i < arity; i++) { if (!HaveSameConstraints(typeParameters1[i], typeMap1, typeParameters2[i], typeMap2)) { return(false); } } return(true); }
// See TypeBind::CheckSingleConstraint. private static bool CheckConstraints( Symbol containingSymbol, ConversionsBase conversions, TypeMap substitution, TypeParameterSymbol typeParameter, TypeSymbol typeArgument, Compilation currentCompilation, ArrayBuilder <TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder) { Debug.Assert(substitution != null); // The type parameters must be original definitions of type parameters from the containing symbol. Debug.Assert(ReferenceEquals(typeParameter.ContainingSymbol, containingSymbol.OriginalDefinition)); if (typeArgument.IsErrorType()) { return(true); } if (typeArgument.IsPointerType() || typeArgument.IsRestrictedType()) { // "The type '{0}' may not be used as a type argument" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BadTypeArgument, typeArgument))); return(false); } if (typeArgument.IsStatic) { // Caller should have already reported ERR_GenericArgIsStaticClass. // (For consistency, consider moving that error reporting here.) return(false); } if (typeParameter.HasReferenceTypeConstraint && !typeArgument.IsReferenceType) { // "The type '{2}' must be a reference type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_RefConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return(false); } if (typeParameter.HasValueTypeConstraint && !typeArgument.IsNonNullableValueType()) { // "The type '{2}' must be a non-nullable value type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ValConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return(false); } // The type parameters for a constructed type/method are the type parameters of // the ConstructedFrom type/method, so the constraint types are not substituted. // For instance with "class C<T, U> where T : U", the type parameter for T in "C<object, int>" // has constraint "U", not "int". We need to substitute the constraints from the // original definition of the type parameters using the map from the constructed symbol. var constraintTypes = ArrayBuilder <TypeSymbol> .GetInstance(); HashSet <DiagnosticInfo> useSiteDiagnostics = null; substitution.SubstituteTypesDistinct(typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), constraintTypes); bool hasError = false; foreach (var constraintType in constraintTypes) { if (SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics)) { continue; } ErrorCode errorCode; if (typeArgument.IsReferenceType) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (typeArgument.IsNullableType()) { errorCode = constraintType.IsInterfaceType() ? ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface : ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else if (typeArgument.TypeKind == TypeKind.TypeParameter) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } SymbolDistinguisher distinguisher = new SymbolDistinguisher(currentCompilation, constraintType, typeArgument); diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(errorCode, containingSymbol.ConstructedFrom(), distinguisher.First, typeParameter, distinguisher.Second))); hasError = true; } if (AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder)) { hasError = true; } constraintTypes.Free(); // Check the constructor constraint. if (typeParameter.HasConstructorConstraint && !SatisfiesConstructorConstraint(typeArgument)) { // "'{2}' must be a non-abstract type with a public parameterless constructor in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return(false); } return(!hasError); }
public static ImmutableArray <T> SubstituteExplicitInterfaceImplementations <T>(ImmutableArray <T> unsubstitutedExplicitInterfaceImplementations, TypeMap map) where T : Symbol { var builder = ArrayBuilder <T> .GetInstance(); foreach (var unsubstitutedPropertyImplemented in unsubstitutedExplicitInterfaceImplementations) { var unsubstitutedInterfaceType = unsubstitutedPropertyImplemented.ContainingType; Debug.Assert((object)unsubstitutedInterfaceType != null); var explicitInterfaceType = map.SubstituteNamedType(unsubstitutedInterfaceType); Debug.Assert((object)explicitInterfaceType != null); var name = unsubstitutedPropertyImplemented.Name; //should already be unqualified T substitutedMemberImplemented = null; foreach (var candidateMember in explicitInterfaceType.GetMembers(name)) { if (candidateMember.OriginalDefinition == unsubstitutedPropertyImplemented.OriginalDefinition) { substitutedMemberImplemented = (T)candidateMember; break; } } Debug.Assert((object)substitutedMemberImplemented != null); //if it was an explicit implementation before the substitution, it should still be after builder.Add(substitutedMemberImplemented); } return(builder.ToImmutableAndFree()); }
/// <summary> /// Returns true if the two partial methods have the same constraints. /// </summary> private static bool HaveSameConstraints(SourceMemberMethodSymbol part1, SourceMemberMethodSymbol part2) { Debug.Assert(!ReferenceEquals(part1, part2)); Debug.Assert(part1.Arity == part2.Arity); var typeParameters1 = part1.TypeParameters; int arity = typeParameters1.Length; if (arity == 0) { return true; } var typeParameters2 = part2.TypeParameters; var indexedTypeParameters = IndexedTypeParameterSymbol.Take(arity); var typeMap1 = new TypeMap(typeParameters1, indexedTypeParameters, allowAlpha: true); var typeMap2 = new TypeMap(typeParameters2, indexedTypeParameters, allowAlpha: true); return MemberSignatureComparer.HaveSameConstraints(typeParameters1, typeMap1, typeParameters2, typeMap2); }
public sealed override TypeSymbol?VisitType(TypeSymbol?type) { return(TypeMap.SubstituteType(type).Type); }
private static bool HaveSameConstraints(ImmutableArray<TypeParameterSymbol> candidateTypeParameters, ImmutableArray<TypeParameterSymbol> desiredTypeParameters) { int arity = candidateTypeParameters.Length; if (arity != desiredTypeParameters.Length) { return false; } else if (arity == 0) { return true; } var indexedTypeParameters = IndexedTypeParameterSymbol.Take(arity); var candidateTypeMap = new TypeMap(candidateTypeParameters, indexedTypeParameters, allowAlpha: true); var desiredTypeMap = new TypeMap(desiredTypeParameters, indexedTypeParameters, allowAlpha: true); return MemberSignatureComparer.HaveSameConstraints(candidateTypeParameters, candidateTypeMap, desiredTypeParameters, desiredTypeMap); }
public bool Equals(Symbol member1, Symbol member2) { if (ReferenceEquals(member1, member2)) { return(true); } if ((object)member1 == null || (object)member2 == null || member1.Kind != member2.Kind) { return(false); } bool sawInterfaceInName1 = false; bool sawInterfaceInName2 = false; if (_considerName) { string name1 = ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(member1.Name); string name2 = ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(member2.Name); sawInterfaceInName1 = name1 != member1.Name; sawInterfaceInName2 = name2 != member2.Name; if (name1 != name2) { return(false); } } // NB: up to, and including, this check, we have not actually forced the (type) parameters // to be expanded - we're only using the counts. int arity = member1.GetMemberArity(); if ((arity != member2.GetMemberArity()) || (member1.GetParameterCount() != member2.GetParameterCount())) { return(false); } TypeMap typeMap1; TypeMap typeMap2; if (arity > 0 && _useSpecialHandlingForNullableTypes) { // We need this special handling in order to avoid forcing resolution of nullable types // in signature of an overriding member while we are looking for a matching overridden member. // Doing the resolution in the original signature can send us into an infinite cycle because // constraints must be inherited from the member we are looking for. // It is important to ensure that the fact whether an indexed type parameter we are about to use // is a reference type is inherited from the corresponding type parameter of the possibly overridden // member (which is member2 when _useSpecialHandlingForNullableTypes is true). This will ensure // proper resolution for nullable types in substituted signature of member1, ensuring proper // comparison of types across both members. ArrayBuilder <TypeParameterSymbol> builder = ArrayBuilder <TypeParameterSymbol> .GetInstance(arity); var typeParameters2 = member2.GetMemberTypeParameters(); for (int i = arity - 1; i >= 0; i--) { builder.Add(IndexedTypeParameterSymbolForOverriding.GetTypeParameter(i, typeParameters2[i].IsValueType)); } var indexed = builder.ToImmutableAndFree(); typeMap1 = new TypeMap(member1.GetMemberTypeParameters(), indexed, true); typeMap2 = new TypeMap(typeParameters2, indexed, true); } else { typeMap1 = GetTypeMap(member1); typeMap2 = GetTypeMap(member2); } if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _typeComparison)) { return(false); } if (member1.GetParameterCount() > 0 && !HaveSameParameterTypes(member1.GetParameters(), typeMap1, member2.GetParameters(), typeMap2, _considerRefKindDifferences, _typeComparison)) { return(false); } if (_considerCallingConvention) { if (GetCallingConvention(member1) != GetCallingConvention(member2)) { return(false); } } else { if (IsVarargMethod(member1) != IsVarargMethod(member2)) { return(false); } } if (_considerExplicitlyImplementedInterfaces) { if (sawInterfaceInName1 != sawInterfaceInName2) { return(false); } // The purpose of this check is to determine whether the interface parts of the member names agree, // but to do so using robust symbolic checks, rather than syntactic ones. Therefore, if neither member // name contains an interface name, this check is not relevant. // Phrased differently, the explicitly implemented interface is not part of the signature unless it's // part of the name. if (sawInterfaceInName1) { Debug.Assert(sawInterfaceInName2); // May avoid realizing interface members. if (member1.IsExplicitInterfaceImplementation() != member2.IsExplicitInterfaceImplementation()) { return(false); } // By comparing symbols, rather than syntax, we gain the flexibility of ignoring whitespace // and gracefully accepting multiple names for the same (or equivalent) types (e.g. "I<int>.M" // vs "I<System.Int32>.M"), but we lose the connection with the name. For example, in metadata, // a method name "I.M" could have nothing to do with "I" but explicitly implement interface "I2". // We will behave as if the method was really named "I2.M". Furthermore, in metadata, a method // can explicitly implement more than one interface method, in which case it doesn't really // make sense to pretend that all of them are part of the signature. var explicitInterfaceImplementations1 = member1.GetExplicitInterfaceImplementations(); var explicitInterfaceImplementations2 = member2.GetExplicitInterfaceImplementations(); if (!explicitInterfaceImplementations1.SetEquals(explicitInterfaceImplementations2, EqualityComparer <Symbol> .Default)) { return(false); } } } return(!_considerTypeConstraints || HaveSameConstraints(member1, typeMap1, member2, typeMap2)); }
internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap) { var otherInstance = (EELocalSymbol)this.Local.ToOtherMethod(method, typeMap); return new DisplayClassInstanceFromLocal(otherInstance); }
/// <summary> /// Check type parameter constraints for the containing type or method symbol. /// </summary> /// <param name="containingSymbol">The generic type or method.</param> /// <param name="conversions">Conversions instance.</param> /// <param name="substitution">The map from type parameters to type arguments.</param> /// <param name="typeParameters">Containing symbol type parameters.</param> /// <param name="typeArguments">Containing symbol type arguments.</param> /// <param name="currentCompilation">Improves error message detail.</param> /// <param name="diagnosticsBuilder">Diagnostics.</param> /// <param name="skipParameters">Parameters to skip.</param> /// <param name="useSiteDiagnosticsBuilder"/> /// <param name="ignoreTypeConstraintsDependentOnTypeParametersOpt">If an original form of a type constraint /// depends on a type parameter from this set, do not verify this type constraint.</param> /// <returns>True if the constraints were satisfied, false otherwise.</returns> public static bool CheckConstraints( this Symbol containingSymbol, ConversionsBase conversions, TypeMap substitution, ImmutableArray<TypeParameterSymbol> typeParameters, ImmutableArray<TypeSymbol> typeArguments, Compilation currentCompilation, ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder, BitVector skipParameters = default(BitVector), HashSet<TypeParameterSymbol> ignoreTypeConstraintsDependentOnTypeParametersOpt = null) { Debug.Assert(typeParameters.Length == typeArguments.Length); Debug.Assert(typeParameters.Length > 0); int n = typeParameters.Length; bool succeeded = true; for (int i = 0; i < n; i++) { if (skipParameters[i]) { continue; } var typeArgument = typeArguments[i]; var typeParameter = typeParameters[i]; if (!CheckConstraints(containingSymbol, conversions, substitution, typeParameter, typeArgument, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder, ignoreTypeConstraintsDependentOnTypeParametersOpt)) { succeeded = false; } } return succeeded; }
private static bool HaveSameReturnTypes(Symbol member1, TypeMap typeMap1, Symbol member2, TypeMap typeMap2, TypeCompareKind typeComparison) { RefKind refKind1; TypeWithAnnotations unsubstitutedReturnType1; ImmutableArray <CustomModifier> refCustomModifiers1; member1.GetTypeOrReturnType(out refKind1, out unsubstitutedReturnType1, out refCustomModifiers1); RefKind refKind2; TypeWithAnnotations unsubstitutedReturnType2; ImmutableArray <CustomModifier> refCustomModifiers2; member2.GetTypeOrReturnType(out refKind2, out unsubstitutedReturnType2, out refCustomModifiers2); // short-circuit type map building in the easiest cases if (refKind1 != refKind2) { return(false); } var isVoid1 = unsubstitutedReturnType1.IsVoidType(); var isVoid2 = unsubstitutedReturnType2.IsVoidType(); if (isVoid1 != isVoid2) { return(false); } if (isVoid1) { if ((typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) != 0 || (unsubstitutedReturnType1.CustomModifiers.IsEmpty && unsubstitutedReturnType2.CustomModifiers.IsEmpty)) { return(true); } } var returnType1 = SubstituteType(typeMap1, unsubstitutedReturnType1); var returnType2 = SubstituteType(typeMap2, unsubstitutedReturnType2); if (!returnType1.Equals(returnType2, typeComparison)) { return(false); } if (((typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) == 0) && !HaveSameCustomModifiers(refCustomModifiers1, typeMap1, refCustomModifiers2, typeMap2)) { return(false); } return(true); }
/// <summary> /// If the extension method is applicable based on the "this" argument type, return /// the method constructed with the inferred type arguments. If the method is not an /// unconstructed generic method, type inference is skipped. If the method is not /// applicable, or if constraints when inferring type parameters from the "this" type /// are not satisfied, the return value is null. /// </summary> public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol method, TypeSymbol thisType, Compilation compilation, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(method.IsExtensionMethod); Debug.Assert((object)thisType != null); if (!method.IsGenericMethod || method != method.ConstructedFrom) { return method; } // We never resolve extension methods on a dynamic receiver. if (thisType.IsDynamic()) { return null; } var containingAssembly = method.ContainingAssembly; var errorNamespace = containingAssembly.GlobalNamespace; var conversions = new TypeConversions(containingAssembly.CorLibrary); // There is absolutely no plausible syntax/tree that we could use for these // synthesized literals. We could be speculatively binding a call to a PE method. var syntaxTree = CSharpSyntaxTree.Dummy; var syntax = (CSharpSyntaxNode)syntaxTree.GetRoot(); // Create an argument value for the "this" argument of specific type, // and pass the same bad argument value for all other arguments. var thisArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, thisType) { WasCompilerGenerated = true }; var otherArgumentType = new ExtendedErrorTypeSymbol(errorNamespace, name: string.Empty, arity: 0, errorInfo: null, unreported: false); var otherArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, otherArgumentType) { WasCompilerGenerated = true }; var paramCount = method.ParameterCount; var arguments = new BoundExpression[paramCount]; var argumentTypes = new TypeSymbol[paramCount]; for (int i = 0; i < paramCount; i++) { var argument = (i == 0) ? thisArgumentValue : otherArgumentValue; arguments[i] = argument; argumentTypes[i] = argument.Type; } var typeArgs = MethodTypeInferrer.InferTypeArgumentsFromFirstArgument( conversions, method, argumentTypes.AsImmutableOrNull(), arguments.AsImmutableOrNull(), ref useSiteDiagnostics); if (typeArgs.IsDefault) { return null; } int firstNullInTypeArgs = -1; // For the purpose of constraint checks we use error type symbol in place of type arguments that we couldn't infer from the first argument. // This prevents constraint checking from failing for corresponding type parameters. var typeArgsForConstraintsCheck = typeArgs; for (int i = 0; i < typeArgsForConstraintsCheck.Length; i++) { if ((object)typeArgsForConstraintsCheck[i] == null) { firstNullInTypeArgs = i; var builder = ArrayBuilder<TypeSymbol>.GetInstance(); builder.AddRange(typeArgs, firstNullInTypeArgs); for (; i < typeArgsForConstraintsCheck.Length; i++) { builder.Add(typeArgsForConstraintsCheck[i] ?? ErrorTypeSymbol.UnknownResultType); } typeArgsForConstraintsCheck = builder.ToImmutableAndFree(); break; } } // Check constraints. var diagnosticsBuilder = ArrayBuilder<TypeParameterDiagnosticInfo>.GetInstance(); var typeParams = method.TypeParameters; var substitution = new TypeMap(typeParams, typeArgsForConstraintsCheck.SelectAsArray(TypeMap.TypeSymbolAsTypeWithModifiers)); ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null; var success = method.CheckConstraints(conversions, substitution, typeParams, typeArgsForConstraintsCheck, compilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder); diagnosticsBuilder.Free(); if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0) { if (useSiteDiagnostics == null) { useSiteDiagnostics = new HashSet<DiagnosticInfo>(); } foreach (var diag in useSiteDiagnosticsBuilder) { useSiteDiagnostics.Add(diag.DiagnosticInfo); } } if (!success) { return null; } // For the purpose of construction we use original type parameters in place of type arguments that we couldn't infer from the first argument. var typeArgsForConstruct = typeArgs; if (firstNullInTypeArgs != -1) { var builder = ArrayBuilder<TypeSymbol>.GetInstance(); builder.AddRange(typeArgs, firstNullInTypeArgs); for (int i = firstNullInTypeArgs; i < typeArgsForConstruct.Length; i++) { builder.Add(typeArgsForConstruct[i] ?? typeParams[i]); } typeArgsForConstruct = builder.ToImmutableAndFree(); } return method.Construct(typeArgsForConstruct); }
public static bool HaveSameConstraints(ImmutableArray <TypeParameterSymbol> typeParameters1, TypeMap typeMap1, ImmutableArray <TypeParameterSymbol> typeParameters2, TypeMap typeMap2, bool includingNullability = false) { Debug.Assert(typeParameters1.Length == typeParameters2.Length); int arity = typeParameters1.Length; for (int i = 0; i < arity; i++) { if (!HaveSameConstraints(typeParameters1[i], typeMap1, typeParameters2[i], typeMap2) || (includingNullability && !HaveSameNullabilityInConstraints(typeParameters1[i], typeMap1, typeParameters2[i], typeMap2, unknownNullabilityMatchesAny: false))) { return(false); } } return(true); }
private TypeMap WithAlphaRename(ImmutableArray<TypeParameterSymbol> oldTypeParameters, Symbol newOwner, out ImmutableArray<TypeParameterSymbol> newTypeParameters) { if (oldTypeParameters.Length == 0) { newTypeParameters = ImmutableArray<TypeParameterSymbol>.Empty; return this; } // Note: the below assertion doesn't hold while rewriting async lambdas defined inside generic methods. // The async rewriter adds a synthesized struct inside the lambda frame and construct a typemap from // the lambda frame's substituted type parameters. // Debug.Assert(!oldTypeParameters.Any(tp => tp is SubstitutedTypeParameterSymbol)); // warning: we expose result to the SubstitutedTypeParameterSymbol constructor, below, even before it's all filled in. TypeMap result = new TypeMap(this.Mapping); ArrayBuilder<TypeParameterSymbol> newTypeParametersBuilder = ArrayBuilder<TypeParameterSymbol>.GetInstance(); // The case where it is "synthesized" is when we're creating type parameters for a synthesized (generic) // class or method for a lambda appearing in a generic method. bool synthesized = !ReferenceEquals(oldTypeParameters[0].ContainingSymbol.OriginalDefinition, newOwner.OriginalDefinition); int ordinal = 0; foreach (var tp in oldTypeParameters) { var newTp = synthesized ? new SynthesizedSubstitutedTypeParameterSymbol(newOwner, result, tp, ordinal) : new SubstitutedTypeParameterSymbol(newOwner, result, tp, ordinal); result.Mapping.Add(tp, new TypeWithModifiers(newTp)); newTypeParametersBuilder.Add(newTp); ordinal++; } newTypeParameters = newTypeParametersBuilder.ToImmutableAndFree(); return result; }
private ExpressionLambdaRewriter(TypeCompilationState compilationState, TypeMap typeMap, CSharpSyntaxNode node, DiagnosticBag diagnostics) { _bound = new SyntheticBoundNodeFactory(null, compilationState.Type, node, compilationState, diagnostics); _ignoreAccessibility = compilationState.ModuleBuilderOpt.IgnoreAccessibility; _int32Type = _bound.SpecialType(SpecialType.System_Int32); _objectType = _bound.SpecialType(SpecialType.System_Object); _nullableType = _bound.SpecialType(SpecialType.System_Nullable_T); _IEnumerableType = _bound.SpecialType(SpecialType.System_Collections_Generic_IEnumerable_T); _typeMap = typeMap; }
internal abstract DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap);
/// <summary> /// If the extension method is applicable based on the "this" argument type, return /// the method constructed with the inferred type arguments. If the method is not an /// unconstructed generic method, type inference is skipped. If the method is not /// applicable, or if constraints when inferring type parameters from the "this" type /// are not satisfied, the return value is null. /// </summary> public static MethodSymbol InferExtensionMethodTypeArguments(this MethodSymbol method, TypeSymbol thisType, Compilation compilation, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(method.IsExtensionMethod); Debug.Assert((object)thisType != null); if (!method.IsGenericMethod || method != method.ConstructedFrom) { return(method); } // We never resolve extension methods on a dynamic receiver. if (thisType.IsDynamic()) { return(null); } var containingAssembly = method.ContainingAssembly; var errorNamespace = containingAssembly.GlobalNamespace; var conversions = new TypeConversions(containingAssembly.CorLibrary); // There is absolutely no plausible syntax/tree that we could use for these // synthesized literals. We could be speculatively binding a call to a PE method. var syntaxTree = CSharpSyntaxTree.Dummy; var syntax = (CSharpSyntaxNode)syntaxTree.GetRoot(); // Create an argument value for the "this" argument of specific type, // and pass the same bad argument value for all other arguments. var thisArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, thisType) { WasCompilerGenerated = true }; var otherArgumentType = new ExtendedErrorTypeSymbol(errorNamespace, name: string.Empty, arity: 0, errorInfo: null, unreported: false); var otherArgumentValue = new BoundLiteral(syntax, ConstantValue.Bad, otherArgumentType) { WasCompilerGenerated = true }; var paramCount = method.ParameterCount; var arguments = new BoundExpression[paramCount]; var argumentTypes = new TypeSymbol[paramCount]; for (int i = 0; i < paramCount; i++) { var argument = (i == 0) ? thisArgumentValue : otherArgumentValue; arguments[i] = argument; argumentTypes[i] = argument.Type; } var typeArgs = MethodTypeInferrer.InferTypeArgumentsFromFirstArgument( conversions, method, argumentTypes.AsImmutableOrNull(), arguments.AsImmutableOrNull(), ref useSiteDiagnostics); if (typeArgs.IsDefault) { return(null); } // Check constraints. var diagnosticsBuilder = ArrayBuilder <TypeParameterDiagnosticInfo> .GetInstance(); var typeParams = method.TypeParameters; var substitution = new TypeMap(typeParams, typeArgs); ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null; var success = method.CheckConstraints(conversions, substitution, method.TypeParameters, typeArgs, compilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder); diagnosticsBuilder.Free(); if (useSiteDiagnosticsBuilder != null && useSiteDiagnosticsBuilder.Count > 0) { if (useSiteDiagnostics == null) { useSiteDiagnostics = new HashSet <DiagnosticInfo>(); } foreach (var diag in useSiteDiagnosticsBuilder) { useSiteDiagnostics.Add(diag.DiagnosticInfo); } } if (!success) { return(null); } return(method.Construct(typeArgs)); }
private static bool HaveSameParameterTypes(ImmutableArray <ParameterSymbol> params1, TypeMap typeMap1, ImmutableArray <ParameterSymbol> params2, TypeMap typeMap2, bool considerRefKindDifferences, TypeCompareKind typeComparison) { Debug.Assert(params1.Length == params2.Length); var numParams = params1.Length; for (int i = 0; i < numParams; i++) { var param1 = params1[i]; var param2 = params2[i]; var type1 = SubstituteType(typeMap1, param1.TypeWithAnnotations); var type2 = SubstituteType(typeMap2, param2.TypeWithAnnotations); if (!type1.Equals(type2, typeComparison)) { return(false); } if ((typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) == 0 && !HaveSameCustomModifiers(param1.RefCustomModifiers, typeMap1, param2.RefCustomModifiers, typeMap2)) { return(false); } var refKind1 = param1.RefKind; var refKind2 = param2.RefKind; // Metadata signatures don't distinguish ref/out, but C# does - even when comparing metadata method signatures. if (considerRefKindDifferences) { if (refKind1 != refKind2) { return(false); } } else { if ((refKind1 == RefKind.None) != (refKind2 == RefKind.None)) { return(false); } } } return(true); }
public static bool HaveSameNullabilityInConstraints(TypeParameterSymbol typeParameter1, TypeMap typeMap1, TypeParameterSymbol typeParameter2, TypeMap typeMap2, bool unknownNullabilityMatchesAny = true) { if (!typeParameter1.IsValueType) { bool?isNotNullableIfReferenceType1 = typeParameter1.IsNotNullableIfReferenceType; bool?isNotNullableIfReferenceType2 = typeParameter2.IsNotNullableIfReferenceType; if (isNotNullableIfReferenceType1 != isNotNullableIfReferenceType2 && !(unknownNullabilityMatchesAny && (!isNotNullableIfReferenceType1.HasValue || !isNotNullableIfReferenceType2.HasValue))) { return(false); } } return(HaveSameTypeConstraints(typeParameter1, typeMap1, typeParameter2, typeMap2, unknownNullabilityMatchesAny ? TypeSymbol.EqualsAllIgnoreOptionsPlusNullableWithUnknownMatchesAnyComparer : TypeSymbol.EqualsAllIgnoreOptionsPlusNullableComparer)); }
public void TypeMap() { var source = @" struct S<T> where T : struct { } "; var comp = CreateCompilationWithMscorlib(source); comp.VerifyDiagnostics(); var intType = comp.GetSpecialType(SpecialType.System_Int32); var customModifiers = ImmutableArray.Create(CSharpCustomModifier.CreateOptional(intType)); var structType = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("S"); var typeParamType = structType.TypeParameters.Single(); var pointerType = new PointerTypeSymbol(typeParamType, customModifiers); // NOTE: We're constructing this manually, since it's illegal. var arrayType = new ArrayTypeSymbol(comp.Assembly, typeParamType, customModifiers); // This is legal, but we're already manually constructing types. var typeMap = new TypeMap(ImmutableArray.Create(typeParamType), ImmutableArray.Create<TypeSymbol>(intType)); var substitutedPointerType = (PointerTypeSymbol)typeMap.SubstituteType(pointerType); var substitutedArrayType = (ArrayTypeSymbol)typeMap.SubstituteType(arrayType); // The map changed the types. Assert.Equal(intType, substitutedPointerType.PointedAtType); Assert.Equal(intType, substitutedArrayType.ElementType); // The map preserved the custom modifiers. Assert.Equal(customModifiers, substitutedPointerType.CustomModifiers); Assert.Equal(customModifiers, substitutedArrayType.CustomModifiers); }
private static TypeWithAnnotations SubstituteType(TypeMap typeMap, TypeWithAnnotations typeSymbol) { return(typeMap == null ? typeSymbol : typeSymbol.SubstituteType(typeMap)); }
// See TypeBind::CheckSingleConstraint. private static bool CheckConstraints( Symbol containingSymbol, ConversionsBase conversions, TypeMap substitution, TypeParameterSymbol typeParameter, TypeSymbol typeArgument, Compilation currentCompilation, ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder, HashSet<TypeParameterSymbol> ignoreTypeConstraintsDependentOnTypeParametersOpt) { Debug.Assert(substitution != null); // The type parameters must be original definitions of type parameters from the containing symbol. Debug.Assert(ReferenceEquals(typeParameter.ContainingSymbol, containingSymbol.OriginalDefinition)); if (typeArgument.IsErrorType()) { return true; } if (typeArgument.IsPointerType() || typeArgument.IsRestrictedType() || typeArgument.SpecialType == SpecialType.System_Void) { // "The type '{0}' may not be used as a type argument" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BadTypeArgument, typeArgument))); return false; } if (typeArgument.IsStatic) { // "'{0}': static types cannot be used as type arguments" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_GenericArgIsStaticClass, typeArgument))); return false; } if (typeParameter.HasReferenceTypeConstraint && !typeArgument.IsReferenceType) { // "The type '{2}' must be a reference type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_RefConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return false; } if (typeParameter.HasValueTypeConstraint && !typeArgument.IsNonNullableValueType()) { // "The type '{2}' must be a non-nullable value type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ValConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return false; } // The type parameters for a constructed type/method are the type parameters of // the ConstructedFrom type/method, so the constraint types are not substituted. // For instance with "class C<T, U> where T : U", the type parameter for T in "C<object, int>" // has constraint "U", not "int". We need to substitute the constraints from the // original definition of the type parameters using the map from the constructed symbol. var constraintTypes = ArrayBuilder<TypeSymbol>.GetInstance(); HashSet<DiagnosticInfo> useSiteDiagnostics = null; substitution.SubstituteTypesDistinctWithoutModifiers(typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), constraintTypes, ignoreTypeConstraintsDependentOnTypeParametersOpt); bool hasError = false; foreach (var constraintType in constraintTypes) { if (SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics)) { continue; } ErrorCode errorCode; if (typeArgument.IsReferenceType) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (typeArgument.IsNullableType()) { errorCode = constraintType.IsInterfaceType() ? ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface : ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else if (typeArgument.TypeKind == TypeKind.TypeParameter) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } SymbolDistinguisher distinguisher = new SymbolDistinguisher(currentCompilation, constraintType, typeArgument); diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(errorCode, containingSymbol.ConstructedFrom(), distinguisher.First, typeParameter, distinguisher.Second))); hasError = true; } if (AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder)) { hasError = true; } constraintTypes.Free(); // Check the constructor constraint. if (typeParameter.HasConstructorConstraint && !SatisfiesConstructorConstraint(typeArgument)) { // "'{2}' must be a non-abstract type with a public parameterless constructor in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return false; } return !hasError; }
private static bool HaveSameCustomModifiers(ImmutableArray <CustomModifier> customModifiers1, TypeMap typeMap1, ImmutableArray <CustomModifier> customModifiers2, TypeMap typeMap2) { // the runtime compares custom modifiers using (effectively) SequenceEqual return(SubstituteModifiers(typeMap1, customModifiers1).SequenceEqual(SubstituteModifiers(typeMap2, customModifiers2))); }
private static ImmutableArray <CustomModifier> SubstituteModifiers(TypeMap typeMap, ImmutableArray <CustomModifier> customModifiers) { return(typeMap == null ? customModifiers : typeMap.SubstituteCustomModifiers(customModifiers)); }
internal SubstitutedParameterSymbol(PropertySymbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) : this((Symbol)containingSymbol, map, originalParameter) { }
internal static BoundNode RewriteLambda(BoundLambda node, TypeCompilationState compilationState, TypeMap typeMap, DiagnosticBag diagnostics) { try { var r = new ExpressionLambdaRewriter(compilationState, typeMap, node.Syntax, diagnostics); var result = r.VisitLambdaInternal(node); if (node.Type != result.Type) { diagnostics.Add(ErrorCode.ERR_MissingPredefinedMember, node.Syntax.Location, r.ExpressionType, "Lambda"); } return result; } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); return node; } }
protected SynthesizedContainer(string name, ImmutableArray <TypeParameterSymbol> typeParameters, TypeMap typeMap) { Debug.Assert(name != null); Debug.Assert(!typeParameters.IsDefault); Debug.Assert(typeMap != null); Name = name; _typeParameters = typeParameters; TypeMap = typeMap; }
internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap) { // Placeholders should be rewritten (as method calls) // rather than copied as locals to the target method. throw ExceptionUtilities.Unreachable; }
protected MethodSymbol VisitMethodSymbol(MethodSymbol method) { if ((object)method == null) { return(null); } if (method.IsTupleMethod) { // Method of a tuple type var oldType = method.ContainingType; var constructedFrom = method.ConstructedFrom; Debug.Assert(oldType.IsTupleType); var newType = (NamedTypeSymbol)TypeMap.SubstituteType(oldType).AsTypeSymbolOnly(); if ((object)newType == oldType) { // tuple type symbol was not rewritten return(constructedFrom.ConstructIfGeneric(TypeMap.SubstituteTypesWithoutModifiers(method.TypeArguments))); } Debug.Assert(newType.IsTupleType); Debug.Assert(oldType.TupleElementTypes.Length == newType.TupleElementTypes.Length); // get a new method by position var oldMembers = oldType.GetMembers(); var newMembers = newType.GetMembers(); Debug.Assert(oldMembers.Length == newMembers.Length); for (int i = 0; i < oldMembers.Length; i++) { if ((object)constructedFrom == oldMembers[i]) { return(((MethodSymbol)newMembers[i]).ConstructIfGeneric(TypeMap.SubstituteTypesWithoutModifiers(method.TypeArguments))); } } throw ExceptionUtilities.Unreachable; } else if (method.ContainingType.IsAnonymousType) { // Method of an anonymous type var newType = (NamedTypeSymbol)TypeMap.SubstituteType(method.ContainingType).AsTypeSymbolOnly(); if (ReferenceEquals(newType, method.ContainingType)) { // Anonymous type symbol was not rewritten return(method); } // get a new method by name foreach (var member in newType.GetMembers(method.Name)) { if (member.Kind == SymbolKind.Method) { return((MethodSymbol)member); } } throw ExceptionUtilities.Unreachable; } else { // Method of a regular type return(((MethodSymbol)method.OriginalDefinition) .AsMember((NamedTypeSymbol)TypeMap.SubstituteType(method.ContainingType).AsTypeSymbolOnly()) .ConstructIfGeneric(TypeMap.SubstituteTypesWithoutModifiers(method.TypeArguments))); } }