public EmbeddedTypeParameter( EmbeddedMethod containingMethod, TypeParameterSymbolAdapter underlyingTypeParameter ) : base(containingMethod, underlyingTypeParameter) { Debug.Assert(underlyingTypeParameter.AdaptedTypeParameterSymbol.IsDefinition); }
public RetargetingTypeParameterSymbol(RetargetingModuleSymbol retargetingModule, TypeParameterSymbol underlyingTypeParameter) : base(underlyingTypeParameter) { Debug.Assert((object)retargetingModule != null); Debug.Assert(!(underlyingTypeParameter is RetargetingTypeParameterSymbol)); _retargetingModule = retargetingModule; }
public static bool DependsOn(this TypeParameterSymbol typeParameter1, TypeParameterSymbol typeParameter2) { Debug.Assert((object)typeParameter1 != null); Debug.Assert((object)typeParameter2 != null); Func<TypeParameterSymbol, IEnumerable<TypeParameterSymbol>> dependencies = x => x.ConstraintTypesNoUseSiteDiagnostics.OfType<TypeParameterSymbol>(); return dependencies.TransitiveClosure(typeParameter1).Contains(typeParameter2); }
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; }
public RetargetingTypeParameterSymbol(RetargetingModuleSymbol retargetingModule, TypeParameterSymbol underlyingTypeParameter) { Debug.Assert((object)retargetingModule != null); Debug.Assert((object)underlyingTypeParameter != null); Debug.Assert(!(underlyingTypeParameter is RetargetingTypeParameterSymbol)); this.retargetingModule = retargetingModule; this.underlyingTypeParameter = underlyingTypeParameter; }
protected sealed override TypeWithModifiers SubstituteTypeParameter(TypeParameterSymbol typeParameter) { // It might need to be substituted directly. TypeWithModifiers result; if (Mapping.TryGetValue(typeParameter, out result)) { return result; } return new TypeWithModifiers(typeParameter); }
protected sealed override TypeSymbol SubstituteTypeParameter(TypeParameterSymbol typeParameter) { // It might need to be substituted directly. TypeSymbol result; if (Mapping.TryGetValue(typeParameter, out result)) { return result; } return typeParameter; }
public EETypeParameterSymbol( Symbol container, TypeParameterSymbol sourceTypeParameter, int ordinal, Func<TypeMap> getTypeMap) { Debug.Assert((container.Kind == SymbolKind.NamedType) || (container.Kind == SymbolKind.Method)); _container = container; _sourceTypeParameter = sourceTypeParameter; _ordinal = ordinal; _getTypeMap = getTypeMap; }
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 sealed override TypeWithModifiers SubstituteTypeParameter(TypeParameterSymbol typeParameter) { // It might need to be substituted directly. TypeWithModifiers result; if (Mapping.TryGetValue(typeParameter, out result)) { if (typeParameter.NullabilityPreservation == CodeAnalysis.Symbols.NullabilityPreservationKind.None && result.Type.Kind == SymbolKind.NonNullableReference) { return new TypeWithModifiers(((NonNullableReferenceTypeSymbol)result.Type).UnderlyingType); } return result; } return new TypeWithModifiers(typeParameter); }
/// <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(); }
private static void GrowPool(int count) { var initialPool = s_parameterPool; while (count > initialPool.Length) { var newPoolSize = ((count + 0x0F) & ~0xF); // grow in increments of 16 var newPool = new TypeParameterSymbol[newPoolSize]; Array.Copy(initialPool, newPool, initialPool.Length); for (int i = initialPool.Length; i < newPool.Length; i++) { newPool[i] = new IndexedTypeParameterSymbol(i); } Interlocked.CompareExchange(ref s_parameterPool, newPool, initialPool); // repeat if race condition occurred and someone else resized the pool before us // and the new pool is still too small initialPool = s_parameterPool; } }
//////////////////////////////////////////////////////////////////////////////// // // Input types // private static bool DoesInputTypeContain(BoundExpression argument, TypeSymbol formalParameterType, TypeParameterSymbol typeParameter) { // SPEC: If E is a method group or an anonymous function and T is a delegate // SPEC: type or expression tree type then all the parameter types of T are // SPEC: input types of E with type T. var delegateType = formalParameterType.GetDelegateType(); if ((object)delegateType == null) { return false; // No input types. } if (argument.Kind != BoundKind.UnboundLambda && argument.Kind != BoundKind.MethodGroup) { return false; // No input types. } var delegateParameters = delegateType.DelegateParameters(); if (delegateParameters.IsDefaultOrEmpty) { return false; } foreach (var delegateParameter in delegateParameters) { if (delegateParameter.Type.ContainsTypeParameter(typeParameter)) { return true; } } return false; }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // { // $anonymous$ local = value as $anonymous$; // return local != null // && System.Collections.Generic.EqualityComparer<T_1>.Default.Equals(this.backingFld_1, local.backingFld_1) // ... // && System.Collections.Generic.EqualityComparer<T_N>.Default.Equals(this.backingFld_N, local.backingFld_N); // } // Type and type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // local BoundAssignmentOperator assignmentToTemp; BoundLocal boundLocal = F.StoreToTemp(F.As(F.Parameter(this.parameters[0]), anonymousType), out assignmentToTemp); // Generate: statement <= 'local = value as $anonymous$' BoundStatement assignment = F.ExpressionStatement(assignmentToTemp); // Generate expression for return statement // retExpression <= 'local != null' BoundExpression retExpression = F.Binary(BinaryOperatorKind.ObjectNotEqual, manager.System_Boolean, F.Convert(manager.System_Object, boundLocal), F.Null(manager.System_Object)); // prepare symbols MethodSymbol equalityComparer_Equals = manager.System_Collections_Generic_EqualityComparer_T__Equals; MethodSymbol equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default; NamedTypeSymbol equalityComparerType = equalityComparer_Equals.ContainingType; // Compare fields for (int index = 0; index < anonymousType.Properties.Length; index++) { // Prepare constructed symbols TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index]; FieldSymbol fieldSymbol = anonymousType.Properties[index].BackingField; NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(typeParameter); // Generate 'retExpression' = 'retExpression && System.Collections.Generic.EqualityComparer<T_index>. // Default.Equals(this.backingFld_index, local.backingFld_index)' retExpression = F.LogicalAnd(retExpression, F.Call(F.StaticCall(constructedEqualityComparer, equalityComparer_get_Default.AsMember(constructedEqualityComparer)), equalityComparer_Equals.AsMember(constructedEqualityComparer), F.Field(F.This(), fieldSymbol), F.Field(boundLocal, fieldSymbol))); } // Final return statement BoundStatement retStatement = F.Return(retExpression); // Create a bound block F.CloseMethod(F.Block(ImmutableArray.Create <LocalSymbol>(boundLocal.LocalSymbol), assignment, retStatement)); }
protected virtual TypeWithModifiers SubstituteTypeParameter(TypeParameterSymbol typeParameter) { return new TypeWithModifiers(typeParameter); }
// 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 void AddSubstitution(ref MutableTypeMap substitution, TypeParameterSymbol tp1, TypeWithModifiers t2) { if (substitution == null) { substitution = new MutableTypeMap(); } // MutableTypeMap.Add will throw if the key has already been added. However, // if t1 was already in the substitution, it would have been substituted at the // start of CanUnifyHelper and we wouldn't be here. substitution.Add(tp1, t2); }
internal void Add(TypeParameterSymbol key, TypeSymbol value) { this.Mapping.Add(key, value); }
public override TypeSymbol GetTypeInferredDuringReduction(TypeParameterSymbol reducedFromTypeParameter) { if ((object)reducedFromTypeParameter == null) { throw new System.ArgumentNullException(); } if (reducedFromTypeParameter.ContainingSymbol != this.reducedFrom) { throw new System.ArgumentException(); } return null; }
internal void Add(TypeParameterSymbol key, TypeWithModifiers value) { this.Mapping.Add(key, value); }
protected virtual TypeSymbolWithAnnotations SubstituteTypeParameter(TypeParameterSymbol typeParameter) { return(TypeSymbolWithAnnotations.Create(typeParameter)); }
protected virtual TypeWithModifiers SubstituteTypeParameter(TypeParameterSymbol typeParameter) { return(new TypeWithModifiers(typeParameter)); }
/// <summary> /// (null TypeParameterSymbol "parameter"): Checks if the given type is a type parameter /// or its referent type is a type parameter (array/pointer) or contains a type parameter (aggregate type) /// (non-null TypeParameterSymbol "parameter"): above + also checks if the type parameter /// is the same as "parameter" /// </summary> public static bool ContainsTypeParameter(this TypeSymbol type, TypeParameterSymbol parameter = null) { var result = type.VisitType(ContainsTypeParameterPredicate, parameter); return((object)result != null); }
public static bool IsMethodTypeParameter(this TypeParameterSymbol p) { return(p.ContainingSymbol.Kind == SymbolKind.Method); }
private static void AddVarianceError <T>( this BindingDiagnosticBag diagnostics, TypeParameterSymbol unsafeTypeParameter, Symbol context, LocationProvider <T> locationProvider, T locationArg, MessageID expectedVariance ) where T : Symbol { MessageID actualVariance; switch (unsafeTypeParameter.Variance) { case VarianceKind.In: actualVariance = MessageID.IDS_Contravariant; break; case VarianceKind.Out: actualVariance = MessageID.IDS_Covariant; break; default: throw ExceptionUtilities.UnexpectedValue(unsafeTypeParameter.Variance); } // Get a location that roughly represents the unsafe type parameter use. // (Typically, the locationProvider will return the location of the entire type // reference rather than the specific type parameter, for instance, returning // "C<T>[]" for "interface I<in T> { C<T>[] F(); }" rather than the type parameter // in "C<T>[]", but that is better than returning the location of T within "I<in T>". var location = locationProvider(locationArg) ?? unsafeTypeParameter.Locations[0]; // CONSIDER: instead of using the same error code for all variance errors, we could use different codes for "requires input-safe", // "requires output-safe", and "requires input-safe and output-safe". This would make the error codes much easier to document and // much more actionable. // UNDONE: related location for use is much more useful if (!(context is TypeSymbol) && context.IsStatic) { diagnostics.Add( ErrorCode.ERR_UnexpectedVarianceStaticMember, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize(), new CSharpRequiredLanguageVersion( MessageID.IDS_FeatureVarianceSafetyForStaticInterfaceMembers.RequiredVersion() ) ); } else { diagnostics.Add( ErrorCode.ERR_UnexpectedVariance, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize() ); } }
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, TypeSymbol.EqualsIgnoringDynamicTupleNamesAndNullabilityComparer)); }
private IEnumerable<ISymbol> LookupTypeParameterMembers(string types, string constraints, string memberName, out TypeParameterSymbol typeParameter) { var template = @" {0} public class C<T> where T : {1} {{ void M() {{ System.Console.WriteLine(/*<bind>*/default(T)/*</bind>*/); }} }} "; var tree = Parse(string.Format(template, types, constraints)); var comp = CreateCompilationWithMscorlibAndSystemCore(new[] { tree }); comp.VerifyDiagnostics(); var model = comp.GetSemanticModel(tree); var classC = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("C"); typeParameter = classC.TypeParameters.Single(); var exprSyntaxToBind = GetExprSyntaxForBinding(GetExprSyntaxList(tree)); Assert.Equal(SyntaxKind.DefaultExpression, exprSyntaxToBind.Kind()); return model.LookupSymbols(exprSyntaxToBind.SpanStart, typeParameter, memberName); }
private static bool HaveSameTypeConstraints(TypeParameterSymbol typeParameter1, TypeMap typeMap1, TypeParameterSymbol typeParameter2, TypeMap typeMap2, EqualityComparer <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 TypeParameterDiagnosticInfo(TypeParameterSymbol typeParameter, DiagnosticInfo diagnosticInfo) { this.TypeParameter = typeParameter; this.DiagnosticInfo = diagnosticInfo; }
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, TypeSymbol.EqualsAllIgnoreOptionsPlusNullableWithUnknownMatchesAnyComparer)); }
private static bool IsValueType(TypeParameterSymbol typeParameter, ImmutableArray<TypeSymbol> constraintTypes) { return typeParameter.HasValueTypeConstraint || TypeParameterSymbol.IsValueTypeFromConstraintTypes(constraintTypes); }
internal bool Equals(TypeParameterSymbol other) { return(Equals(other, TypeCompareKind.ConsiderEverything)); }
public virtual void VisitTypeParameter(TypeParameterSymbol symbol) { DefaultVisit(symbol); }
public ImmutableArray <CustomModifier> GetTypeArgumentsCustomModifiersFor(TypeParameterSymbol originalDefinition) { Debug.Assert((object)originalDefinition != null); Debug.Assert(originalDefinition.IsDefinition); return(SubstituteTypeParameter(originalDefinition).CustomModifiers); }
internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) { this.Manager = manager; this.TypeDescriptorKey = typeDescr.Key; _smallestLocation = typeDescr.Location; // Will be set when the type's metadata is ready to be emitted, // <anonymous-type>.Name will throw exception if requested // before that moment. _nameAndIndex = null; int fieldsCount = typeDescr.Fields.Length; // members Symbol[] members = new Symbol[fieldsCount * 3 + 1]; int memberIndex = 0; // The array storing property symbols to be used in // generation of constructor and other methods if (fieldsCount > 0) { AnonymousTypePropertySymbol[] propertiesArray = new AnonymousTypePropertySymbol[fieldsCount]; TypeParameterSymbol[] typeParametersArray = new TypeParameterSymbol[fieldsCount]; // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { AnonymousTypeField field = typeDescr.Fields[fieldIndex]; // Add a type parameter AnonymousTypeParameterSymbol typeParameter = new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name)); typeParametersArray[fieldIndex] = typeParameter; // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, field, typeParameter); propertiesArray[fieldIndex] = property; // Property related symbols members[memberIndex++] = property; members[memberIndex++] = property.BackingField; members[memberIndex++] = property.GetMethod; } _typeParameters = typeParametersArray.AsImmutable(); this.Properties = propertiesArray.AsImmutable(); } else { _typeParameters = ImmutableArray<TypeParameterSymbol>.Empty; this.Properties = ImmutableArray<AnonymousTypePropertySymbol>.Empty; } // Add a constructor members[memberIndex++] = new AnonymousTypeConstructorSymbol(this, this.Properties); _members = members.AsImmutable(); Debug.Assert(memberIndex == _members.Length); // fill nameToSymbols map foreach (var symbol in _members) { _nameToSymbols.Add(symbol.Name, symbol); } // special members: Equals, GetHashCode, ToString MethodSymbol[] specialMembers = new MethodSymbol[3]; specialMembers[0] = new AnonymousTypeEqualsMethodSymbol(this); specialMembers[1] = new AnonymousTypeGetHashCodeMethodSymbol(this); specialMembers[2] = new AnonymousTypeToStringMethodSymbol(this); this.SpecialMembers = specialMembers.AsImmutable(); }
// 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() || 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); 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); }
internal bool Equals(TypeParameterSymbol other) { return(Equals(other, false, false)); }
private static bool IsValueType(TypeParameterSymbol typeParameter, ImmutableArray <TypeSymbol> constraintTypes) { return(typeParameter.HasValueTypeConstraint || TypeParameterSymbol.IsValueTypeFromConstraintTypes(constraintTypes)); }
private void AddExactBound(TypeParameterSymbol methodTypeParameter, TypeSymbol exactBound) { Debug.Assert(IsUnfixedTypeParameter(methodTypeParameter)); int methodTypeParameterIndex = methodTypeParameter.Ordinal; if (_exactBounds[methodTypeParameterIndex] == null) { _exactBounds[methodTypeParameterIndex] = new HashSet<TypeSymbol>(); } _exactBounds[methodTypeParameterIndex].Add(exactBound); }
private static TypeParameterDiagnosticInfo GenerateConflictingConstraintsError(TypeParameterSymbol typeParameter, TypeSymbol deducedBase, bool classConflict) { // "Type parameter '{0}' inherits conflicting constraints '{1}' and '{2}'" return(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BaseConstraintConflict, typeParameter, deducedBase, classConflict ? "class" : "struct"))); }
//////////////////////////////////////////////////////////////////////////////// // // Output types // private static bool DoesOutputTypeContain(BoundExpression argument, TypeSymbol formalParameterType, TypeParameterSymbol typeParameter) { // SPEC: If E is a method group or an anonymous function and T is a delegate // SPEC: type or expression tree type then the return type of T is an output type // SPEC: of E with type T. var delegateType = formalParameterType.GetDelegateType(); if ((object)delegateType == null) { return false; } if (argument.Kind != BoundKind.UnboundLambda && argument.Kind != BoundKind.MethodGroup) { return false; } MethodSymbol delegateInvoke = delegateType.DelegateInvokeMethod; if ((object)delegateInvoke == null || delegateInvoke.HasUseSiteError) { return false; } var delegateReturnType = delegateInvoke.ReturnType; if ((object)delegateReturnType == null) { return false; } return delegateReturnType.ContainsTypeParameter(typeParameter); }
// Based on SymbolLoader::ResolveBounds. public static TypeParameterBounds ResolveBounds( this TypeParameterSymbol typeParameter, AssemblySymbol corLibrary, ConsList <TypeParameterSymbol> inProgress, ImmutableArray <TypeSymbol> constraintTypes, bool inherited, CSharpCompilation currentCompilation, ArrayBuilder <TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder) { Debug.Assert(currentCompilation == null || typeParameter.IsFromCompilation(currentCompilation)); ImmutableArray <NamedTypeSymbol> interfaces; NamedTypeSymbol effectiveBaseClass = corLibrary.GetSpecialType(typeParameter.HasValueTypeConstraint ? SpecialType.System_ValueType : SpecialType.System_Object); TypeSymbol deducedBaseType = effectiveBaseClass; DynamicTypeEraser dynamicEraser = null; if (constraintTypes.Length == 0) { interfaces = ImmutableArray <NamedTypeSymbol> .Empty; } else { var constraintTypesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(); var interfacesBuilder = ArrayBuilder <NamedTypeSymbol> .GetInstance(); var conversions = new TypeConversions(corLibrary); HashSet <DiagnosticInfo> useSiteDiagnostics = null; // Resolve base types, determine the effective base class and // interfaces, and filter out any constraint types that cause cycles. foreach (var constraintType in constraintTypes) { NamedTypeSymbol constraintEffectiveBase; TypeSymbol constraintDeducedBase; switch (constraintType.TypeKind) { case TypeKind.Dynamic: Debug.Assert(inherited || currentCompilation == null); continue; case TypeKind.TypeParameter: { var containingSymbol = typeParameter.ContainingSymbol; var constraintTypeParameter = (TypeParameterSymbol)constraintType; ConsList <TypeParameterSymbol> constraintsInProgress; if (constraintTypeParameter.ContainingSymbol == containingSymbol) { // The constraint type parameter is from the same containing type or method. if (inProgress.ContainsReference(constraintTypeParameter)) { // "Circular constraint dependency involving '{0}' and '{1}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(constraintTypeParameter, new CSDiagnosticInfo(ErrorCode.ERR_CircularConstraint, constraintTypeParameter, typeParameter))); continue; } constraintsInProgress = inProgress; } else { // The constraint type parameter is from a different containing symbol so no cycle. constraintsInProgress = ConsList <TypeParameterSymbol> .Empty; } // Use the calculated bounds from the constraint type parameter. constraintEffectiveBase = constraintTypeParameter.GetEffectiveBaseClass(constraintsInProgress); constraintDeducedBase = constraintTypeParameter.GetDeducedBaseType(constraintsInProgress); AddInterfaces(interfacesBuilder, constraintTypeParameter.GetInterfaces(constraintsInProgress)); if (constraintTypeParameter.HasValueTypeConstraint && !inherited && currentCompilation != null && constraintTypeParameter.IsFromCompilation(currentCompilation)) { // "Type parameter '{1}' has the 'struct' constraint so '{1}' cannot be used as a constraint for '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ConWithValCon, typeParameter, constraintTypeParameter))); continue; } } break; case TypeKind.Interface: case TypeKind.Class: case TypeKind.Delegate: NamedTypeSymbol erasedConstraintType; if (inherited || currentCompilation == null) { // only inherited constraints may contain dynamic if (dynamicEraser == null) { dynamicEraser = new DynamicTypeEraser(corLibrary.GetSpecialType(SpecialType.System_Object)); } erasedConstraintType = (NamedTypeSymbol)dynamicEraser.EraseDynamic(constraintType); } else { Debug.Assert(!constraintType.ContainsDynamic()); Debug.Assert(constraintType.TypeKind != TypeKind.Delegate); erasedConstraintType = (NamedTypeSymbol)constraintType; } if (constraintType.IsInterfaceType()) { AddInterface(interfacesBuilder, erasedConstraintType); constraintTypesBuilder.Add(constraintType); continue; } else { constraintEffectiveBase = erasedConstraintType; constraintDeducedBase = constraintType; break; } case TypeKind.Struct: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_ValueType); constraintDeducedBase = constraintType; break; case TypeKind.Enum: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_Enum); constraintDeducedBase = constraintType; break; case TypeKind.Array: Debug.Assert(inherited || currentCompilation == null); constraintEffectiveBase = corLibrary.GetSpecialType(SpecialType.System_Array); constraintDeducedBase = constraintType; break; case TypeKind.Error: constraintEffectiveBase = (NamedTypeSymbol)constraintType; constraintDeducedBase = constraintType; break; case TypeKind.Submission: default: throw ExceptionUtilities.UnexpectedValue(constraintType.TypeKind); } CheckEffectiveAndDeducedBaseTypes(conversions, constraintEffectiveBase, constraintDeducedBase); constraintTypesBuilder.Add(constraintType); // Determine the more encompassed of the current effective base // class and the previously computed effective base class. if (!deducedBaseType.IsErrorType() && !constraintDeducedBase.IsErrorType()) { if (!IsEncompassedBy(conversions, deducedBaseType, constraintDeducedBase, ref useSiteDiagnostics)) { if (!IsEncompassedBy(conversions, constraintDeducedBase, deducedBaseType, ref useSiteDiagnostics)) { // "Type parameter '{0}' inherits conflicting constraints '{1}' and '{2}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BaseConstraintConflict, typeParameter, constraintDeducedBase, deducedBaseType))); } else { deducedBaseType = constraintDeducedBase; effectiveBaseClass = constraintEffectiveBase; } } } } AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder); CheckEffectiveAndDeducedBaseTypes(conversions, effectiveBaseClass, deducedBaseType); constraintTypes = constraintTypesBuilder.ToImmutableAndFree(); interfaces = interfacesBuilder.ToImmutableAndFree(); } Debug.Assert((effectiveBaseClass.SpecialType == SpecialType.System_Object) || (deducedBaseType.SpecialType != SpecialType.System_Object)); // Only create a TypeParameterBounds instance for this type // parameter if the bounds are not the default values. if ((constraintTypes.Length == 0) && (deducedBaseType.SpecialType == SpecialType.System_Object)) { Debug.Assert(effectiveBaseClass.SpecialType == SpecialType.System_Object); Debug.Assert(interfaces.Length == 0); return(null); } var bounds = new TypeParameterBounds(constraintTypes, interfaces, effectiveBaseClass, deducedBaseType); // Additional constraint checks for overrides. if (inherited) { CheckOverrideConstraints(typeParameter, bounds, diagnosticsBuilder); } return(bounds); }
public EmbeddedTypeParameter(EmbeddedMethod containingMethod, TypeParameterSymbol underlyingTypeParameter) : base(containingMethod, underlyingTypeParameter) { Debug.Assert(underlyingTypeParameter.IsDefinition); }
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); } // 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>(TypeSymbol.EqualsIgnoringDynamicAndTupleNamesComparer); var substitutedTypes2 = new HashSet <TypeSymbol>(TypeSymbol.EqualsIgnoringDynamicAndTupleNamesComparer); SubstituteConstraintTypes(constraintTypes1, typeMap1, substitutedTypes1); SubstituteConstraintTypes(constraintTypes2, typeMap2, substitutedTypes2); return(AreConstraintTypesSubset(substitutedTypes1, substitutedTypes2, typeParameter2) && AreConstraintTypesSubset(substitutedTypes2, substitutedTypes1, typeParameter1)); }
private static bool IsVarianceUnsafe <T>( TypeSymbol type, bool requireOutputSafety, bool requireInputSafety, Symbol context, LocationProvider <T> locationProvider, T locationArg, BindingDiagnosticBag diagnostics ) where T : Symbol { Debug.Assert(requireOutputSafety || requireInputSafety); // A type T is "output-unsafe" ["input-unsafe"] if one of the following holds: switch (type.Kind) { case SymbolKind.TypeParameter: // 1) T is a contravariant [covariant] type parameter TypeParameterSymbol typeParam = (TypeParameterSymbol)type; if ( requireInputSafety && requireOutputSafety && typeParam.Variance != VarianceKind.None ) { // This sub-case isn't mentioned in the spec, because it's not required for // the definition. It just allows us to give a better error message for // type parameters that are both output-unsafe and input-unsafe. diagnostics.AddVarianceError( typeParam, context, locationProvider, locationArg, MessageID.IDS_Invariantly ); return(true); } else if (requireOutputSafety && typeParam.Variance == VarianceKind.In) { // The is output-unsafe case (1) from the spec. diagnostics.AddVarianceError( typeParam, context, locationProvider, locationArg, MessageID.IDS_Covariantly ); return(true); } else if (requireInputSafety && typeParam.Variance == VarianceKind.Out) { // The is input-unsafe case (1) from the spec. diagnostics.AddVarianceError( typeParam, context, locationProvider, locationArg, MessageID.IDS_Contravariantly ); return(true); } else { return(false); } case SymbolKind.ArrayType: // 2) T is an array type with an output-unsafe [input-unsafe] element type return(IsVarianceUnsafe( ((ArrayTypeSymbol)type).ElementType, requireOutputSafety, requireInputSafety, context, locationProvider, locationArg, diagnostics )); case SymbolKind.ErrorType: case SymbolKind.NamedType: var namedType = (NamedTypeSymbol)type; // 3) (see IsVarianceUnsafe(NamedTypeSymbol)) return(IsVarianceUnsafe( namedType, requireOutputSafety, requireInputSafety, context, locationProvider, locationArg, diagnostics )); default: return(false); } }
/// <summary> /// 3) T is an interface, class, struct, enum, or delegate type <![CDATA[S<A_1, ..., A_k>]]> constructed /// from a generic type <![CDATA[S<X_1, ..., X_k>]]> where for at least one A_i one /// of the following holds: /// a) X_i is covariant or invariant and A_i is output-unsafe [input-unsafe] /// b) X_i is contravariant or invariant and A_i is input-unsafe [output-unsafe] (note: spec has "input-safe", but it's a typo) /// </summary> /// <remarks> /// Slight rewrite to make it more idiomatic for C#: /// a) X_i is covariant and A_i is input-unsafe /// b) X_i is contravariant and A_i is output-unsafe /// c) X_i is invariant and A_i is input-unsafe or output-unsafe /// </remarks> private static bool IsVarianceUnsafe <T>( NamedTypeSymbol namedType, bool requireOutputSafety, bool requireInputSafety, Symbol context, LocationProvider <T> locationProvider, T locationArg, DiagnosticBag diagnostics) where T : Symbol { Debug.Assert(requireOutputSafety || requireInputSafety); switch (namedType.TypeKind) { case TypeKind.Class: case TypeKind.Struct: case TypeKind.Enum: // Can't be generic, but can be nested in generic. case TypeKind.Interface: case TypeKind.Delegate: case TypeKind.Error: break; default: return(false); } while ((object)namedType != null) { for (int i = 0; i < namedType.Arity; i++) { TypeParameterSymbol typeParam = namedType.TypeParameters[i]; TypeSymbol typeArg = namedType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[i].Type; bool requireOut; bool requireIn; switch (typeParam.Variance) { case VarianceKind.Out: // a) X_i is covariant and A_i is output-unsafe [input-unsafe] requireOut = requireOutputSafety; requireIn = requireInputSafety; break; case VarianceKind.In: // b) X_i is contravariant and A_i is input-unsafe [output-unsafe] requireOut = requireInputSafety; requireIn = requireOutputSafety; break; case VarianceKind.None: // c) X_i is invariant and A_i is output-unsafe or input-unsafe requireIn = true; requireOut = true; break; default: throw ExceptionUtilities.UnexpectedValue(typeParam.Variance); } if (IsVarianceUnsafe(typeArg, requireOut, requireIn, context, locationProvider, locationArg, diagnostics)) { return(true); } } namedType = namedType.ContainingType; } return(false); }
public override TypeSymbol GetTypeInferredDuringReduction(TypeParameterSymbol reducedFromTypeParameter) { // This will throw if API shouldn't be supported or there is a problem with the argument. var notUsed = originalDefinition.GetTypeInferredDuringReduction(reducedFromTypeParameter); Debug.Assert((object)notUsed == null && (object)originalDefinition.ReducedFrom != null); return this.TypeArguments[reducedFromTypeParameter.Ordinal]; }
protected virtual TypeSymbol SubstituteTypeParameter(TypeParameterSymbol typeParameter) { return(typeParameter); }
// Based on SymbolLoader::SetOverrideConstraints. private static void CheckOverrideConstraints( TypeParameterSymbol typeParameter, TypeParameterBounds bounds, ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder) { var deducedBase = bounds.DeducedBaseType; var constraintTypes = bounds.ConstraintTypes; if (IsValueType(typeParameter, constraintTypes) && IsReferenceType(typeParameter, constraintTypes)) { Debug.Assert(!deducedBase.IsValueType || typeParameter.HasReferenceTypeConstraint); diagnosticsBuilder.Add(GenerateConflictingConstraintsError(typeParameter, deducedBase, classConflict: deducedBase.IsValueType)); } else if (deducedBase.IsNullableType() && (typeParameter.HasValueTypeConstraint || typeParameter.HasReferenceTypeConstraint)) { diagnosticsBuilder.Add(GenerateConflictingConstraintsError(typeParameter, deducedBase, classConflict: typeParameter.HasReferenceTypeConstraint)); } }
public TypeParameterDiagnosticInfo(TypeParameterSymbol typeParameter, DiagnosticInfo diagnosticInfo) { this.TypeParameter = typeParameter; this.DiagnosticInfo = diagnosticInfo; }
private static bool AppendUseSiteDiagnostics( HashSet<DiagnosticInfo> useSiteDiagnostics, TypeParameterSymbol typeParameter, ref ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder) { if (useSiteDiagnostics.IsNullOrEmpty()) { return false; } if (useSiteDiagnosticsBuilder == null) { useSiteDiagnosticsBuilder = new ArrayBuilder<TypeParameterDiagnosticInfo>(); } bool hasErrors = false; foreach (var info in useSiteDiagnostics) { if (info.Severity == DiagnosticSeverity.Error) { hasErrors = true; } useSiteDiagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, info)); } return hasErrors; }
public SynthesizedTypeParameterSymbol(Symbol owner, TypeMap map, TypeParameterSymbol substitutedFrom) : base(owner, map, substitutedFrom) { }
private static TypeParameterDiagnosticInfo GenerateConflictingConstraintsError(TypeParameterSymbol typeParameter, TypeSymbol deducedBase, bool classConflict) { // "Type parameter '{0}' inherits conflicting constraints '{1}' and '{2}'" return new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BaseConstraintConflict, typeParameter, deducedBase, classConflict ? "class" : "struct")); }
internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousTypeDescriptor typeDescr) { this.Manager = manager; this.TypeDescriptorKey = typeDescr.Key; _smallestLocation = typeDescr.Location; // Will be set when the type's metadata is ready to be emitted, // <anonymous-type>.Name will throw exception if requested // before that moment. _nameAndIndex = null; int fieldsCount = typeDescr.Fields.Length; // members Symbol[] members = new Symbol[fieldsCount * 3 + 1]; int memberIndex = 0; // The array storing property symbols to be used in // generation of constructor and other methods if (fieldsCount > 0) { AnonymousTypePropertySymbol[] propertiesArray = new AnonymousTypePropertySymbol[fieldsCount]; TypeParameterSymbol[] typeParametersArray = new TypeParameterSymbol[fieldsCount]; // Process fields for (int fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex++) { AnonymousTypeField field = typeDescr.Fields[fieldIndex]; // Add a type parameter AnonymousTypeParameterSymbol typeParameter = new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name)); typeParametersArray[fieldIndex] = typeParameter; // Add a property AnonymousTypePropertySymbol property = new AnonymousTypePropertySymbol(this, field, typeParameter); propertiesArray[fieldIndex] = property; // Property related symbols members[memberIndex++] = property; members[memberIndex++] = property.BackingField; members[memberIndex++] = property.GetMethod; } _typeParameters = typeParametersArray.AsImmutable(); this.Properties = propertiesArray.AsImmutable(); } else { _typeParameters = ImmutableArray <TypeParameterSymbol> .Empty; this.Properties = ImmutableArray <AnonymousTypePropertySymbol> .Empty; } // Add a constructor members[memberIndex++] = new AnonymousTypeConstructorSymbol(this, this.Properties); _members = members.AsImmutable(); Debug.Assert(memberIndex == _members.Length); // fill nameToSymbols map foreach (var symbol in _members) { _nameToSymbols.Add(symbol.Name, symbol); } // special members: Equals, GetHashCode, ToString MethodSymbol[] specialMembers = new MethodSymbol[3]; specialMembers[0] = new AnonymousTypeEqualsMethodSymbol(this); specialMembers[1] = new AnonymousTypeGetHashCodeMethodSymbol(this); specialMembers[2] = new AnonymousTypeToStringMethodSymbol(this); this.SpecialMembers = specialMembers.AsImmutable(); }
/// <summary> /// Return true if the given type contains the specified type parameter. /// </summary> private static bool Contains(TypeSymbol type, TypeParameterSymbol typeParam) { switch (type.Kind) { case SymbolKind.ArrayType: return Contains(((ArrayTypeSymbol)type).ElementType, typeParam); case SymbolKind.PointerType: return Contains(((PointerTypeSymbol)type).PointedAtType, typeParam); case SymbolKind.NamedType: case SymbolKind.ErrorType: { NamedTypeSymbol namedType = (NamedTypeSymbol)type; while ((object)namedType != null) { ImmutableArray<TypeSymbol> typeParts = namedType.IsTupleType ? namedType.TupleElementTypes : namedType.TypeArgumentsNoUseSiteDiagnostics; foreach (TypeSymbol typePart in typeParts) { if (Contains(typePart, typeParam)) { return true; } } namedType = namedType.ContainingType; } return false; } case SymbolKind.TypeParameter: return type == typeParam; default: return false; } }
public WrappedTypeParameterSymbol(TypeParameterSymbol underlyingTypeParameter) { Debug.Assert((object)underlyingTypeParameter != null); _underlyingTypeParameter = underlyingTypeParameter; }
/// <summary> /// Returns true if the first set of constraint types /// is a subset of the second set. /// </summary> private static bool AreConstraintTypesSubset(HashSet <TypeSymbol> constraintTypes1, HashSet <TypeSymbol> constraintTypes2, TypeParameterSymbol typeParameter2) { foreach (var constraintType in constraintTypes1) { // Skip object type (spec. 13.4.3). if (constraintType.SpecialType == SpecialType.System_Object) { continue; } if (constraintTypes2.Contains(constraintType)) { continue; } // The struct constraint implies a System.ValueType constraint // type which may be explicit in the other type parameter // constraints (through type substitution in derived types). if ((constraintType.SpecialType == SpecialType.System_ValueType) && typeParameter2.HasValueTypeConstraint) { continue; } return(false); } return(true); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) { AnonymousTypeManager manager = ((AnonymousTypeTemplateSymbol)this.ContainingType).Manager; SyntheticBoundNodeFactory F = this.CreateBoundNodeFactory(compilationState, diagnostics); // Method body: // // HASH_FACTOR = 0xa5555529; // INIT_HASH = (...((0 * HASH_FACTOR) + backingFld_1.Name.GetHashCode()) * HASH_FACTOR // + backingFld_2.Name.GetHashCode()) * HASH_FACTOR // + ... // + backingFld_N.Name.GetHashCode() // // { // return (...((INITIAL_HASH * HASH_FACTOR) + EqualityComparer<T_1>.Default.GetHashCode(this.backingFld_1)) * HASH_FACTOR // + EqualityComparer<T_2>.Default.GetHashCode(this.backingFld_2)) * HASH_FACTOR // ... // + EqualityComparer<T_N>.Default.GetHashCode(this.backingFld_N) // } const int HASH_FACTOR = -1521134295; // (int)0xa5555529 // Type expression AnonymousTypeTemplateSymbol anonymousType = (AnonymousTypeTemplateSymbol)this.ContainingType; // INIT_HASH int initHash = 0; foreach (var property in anonymousType.Properties) { initHash = unchecked (initHash * HASH_FACTOR + property.BackingField.Name.GetHashCode()); } // Generate expression for return statement // retExpression <= 'INITIAL_HASH' BoundExpression retExpression = F.Literal(initHash); // prepare symbols MethodSymbol equalityComparer_GetHashCode = manager.System_Collections_Generic_EqualityComparer_T__GetHashCode; MethodSymbol equalityComparer_get_Default = manager.System_Collections_Generic_EqualityComparer_T__get_Default; NamedTypeSymbol equalityComparerType = equalityComparer_GetHashCode.ContainingType; // bound HASH_FACTOR BoundLiteral boundHashFactor = F.Literal(HASH_FACTOR); // Process fields for (int index = 0; index < anonymousType.Properties.Length; index++) { // Prepare constructed symbols TypeParameterSymbol typeParameter = anonymousType.TypeParameters[index]; NamedTypeSymbol constructedEqualityComparer = equalityComparerType.Construct(typeParameter); // Generate 'retExpression' <= 'retExpression * HASH_FACTOR retExpression = F.Binary(BinaryOperatorKind.IntMultiplication, manager.System_Int32, retExpression, boundHashFactor); // Generate 'retExpression' <= 'retExpression + EqualityComparer<T_index>.Default.GetHashCode(this.backingFld_index)' retExpression = F.Binary(BinaryOperatorKind.IntAddition, manager.System_Int32, retExpression, F.Call( F.StaticCall(constructedEqualityComparer, equalityComparer_get_Default.AsMember(constructedEqualityComparer)), equalityComparer_GetHashCode.AsMember(constructedEqualityComparer), F.Field(F.This(), anonymousType.Properties[index].BackingField))); } // Create a bound block F.CloseMethod(F.Block(F.Return(retExpression))); }
private static void CheckConstraints( TypeParameterSymbol typeParameter, TypeParameterConstraintKind constraints, bool isValueType, bool isReferenceType, string effectiveBaseClassDescription, string deducedBaseTypeDescription, params string[] constraintTypeDescriptions) { Assert.Equal(constraints, Utils.GetTypeParameterConstraints(typeParameter)); Assert.Equal(typeParameter.IsValueType, isValueType); Assert.Equal(typeParameter.IsReferenceType, isReferenceType); Assert.Null(typeParameter.BaseType); Assert.Equal(typeParameter.Interfaces.Length, 0); Utils.CheckSymbol(typeParameter.EffectiveBaseClassNoUseSiteDiagnostics, effectiveBaseClassDescription); Utils.CheckSymbol(typeParameter.DeducedBaseTypeNoUseSiteDiagnostics, deducedBaseTypeDescription); Utils.CheckSymbols(typeParameter.ConstraintTypes, constraintTypeDescriptions); }
/// <summary> /// If this method is a reduced extension method, returns a type inferred during reduction process for the type parameter. /// </summary> /// <param name="reducedFromTypeParameter">Type parameter of the corresponding <see cref="ReducedFrom"/> method.</param> /// <returns>Inferred type or Nothing if nothing was inferred.</returns> /// <exception cref="System.InvalidOperationException">If this is not a reduced extension method.</exception> /// <exception cref="System.ArgumentNullException">If <paramref name="reducedFromTypeParameter"/> is null.</exception> /// <exception cref="System.ArgumentException">If <paramref name="reducedFromTypeParameter"/> doesn't belong to the corresponding <see cref="ReducedFrom"/> method.</exception> public virtual TypeSymbol GetTypeInferredDuringReduction(TypeParameterSymbol reducedFromTypeParameter) { throw new InvalidOperationException(); }