void CheckCircular(TypeParameterSpec p, TypeParameterSpec baseType, ResolveContext rc, bool ignoreFirst = false, TypeParameterSpec parent = null) { if (p == baseType && !ignoreFirst) { rc.Report.Error(173, Location, "Circular constraint dependency involving `{0}' and `{1}'", p.Name, parent.Name); return; } foreach (var t in baseType.DirectBaseTypes.Where(x => x is TypeParameterSpec)) { CheckCircular(p, t as TypeParameterSpec, rc, false, baseType); } }
public bool DoResolve(Resolver.ResolveContext rc) { ResolvedTypeParameter = CreateResolvedTypeParameter(rc.CurrentTypeResolveContext); // check for conflicting constraints (struct & class) // if(ResolvedTypeParameter.HasReferenceTypeConstraint && ResolvedTypeParameter.HasValueTypeConstraint ) // rc.Report.Error(174, Location, //"Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'", //name, "struct","class"); // check direct base types List <IType> checked_types = new List <IType>(); foreach (var type in ResolvedTypeParameter.DirectBaseTypes) { // check for duplicate constraints if (checked_types.Contains(type)) { rc.Report.Error(176, Location, "Duplicate constraint `{0}' for type parameter `{1}'", type.ToString(), name); continue; } checked_types.Add(type); // check accessibility of type & constraint if (!ResolvedTypeParameter.Owner.IsAccessibleAs(type)) { rc.Report.Error(177, Location, "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'", type.ToString(), ResolvedTypeParameter.Owner.ToString()); } if (type is TypeParameterSpec) { TypeParameterSpec t = (type as TypeParameterSpec); if (t.HasValueTypeConstraint) { rc.Report.Error(178, Location, "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'", t.Name, name); } // check for circular CheckCircular(t, t, rc, true); // // Checks whether there are no conflicts between type parameter constraints // // class Foo<T, U> // where T : A // where U : B, T // // A and B are not convertible and only 1 class constraint is allowed //TODO: Add Conversion check // check for class type and (class or struct constraint) if ((t.HasValueTypeConstraint && ResolvedTypeParameter.HasReferenceTypeConstraint) || (t.HasReferenceTypeConstraint && ResolvedTypeParameter.HasValueTypeConstraint)) { rc.Report.Error(179, Location, "`{0}' and `{1}' : cannot specify both `class' and `struct' constraint", t.Name, Name); } } else { // check static or sealed if ((type as IEntity).IsSealed) { rc.Report.Error(180, Location, "`{0}' A constraint must be an interface, a type parameter or a non sealed/static class", type.ToString()); } } // primitive types check if (type.IsBuiltinType()) { rc.Report.Error(182, Location, "The type `{0}' cannot not be used as a base type for type parameter `{1}' in type or method `{2}'. ", type.ToString(), name, ResolvedTypeParameter.Owner.ToString()); } } // constructor constraint if (ResolvedTypeParameter.HasDefaultConstructorConstraint && !ResolvedTypeParameter.EffectiveBaseClass.GetConstructors(x => x.Parameters.Count == 0).Any()) { rc.Report.Error(181, Location, "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'", ResolvedTypeParameter.EffectiveBaseClass.ToString(), name, ResolvedTypeParameter.Owner.ToString()); } return(true); }