// TODO: Remove this code and rely on GetAssemblyDefinition only
//
var module = new Compiler.ModuleContainer (cc);
+ module.HasTypesFullyDefined = true;
var temp = new Compiler.AssemblyDefinitionDynamic (module, "dynamic");
module.SetDeclaringAssembly (temp);
}
}
- public bool HasUnresolvedConstraints {
- get {
- return false;
- }
- }
-
public bool IsObsolete {
get {
// Always true to ignore obsolete attribute checks
--- /dev/null
+// CS0310: The type `Class1' must have a public parameterless constructor in order to use it as parameter `T' in the generic type or method `Class3<T>'
+// Line: 18
+
+public class Class1
+{
+ public Class1 (int i) { }
+}
+
+public class Class2<T>
+{
+}
+
+public class Class3<T> where T : new ()
+{
+}
+
+
+class A : Class2<Class3<Class1>>
+{
+}
+
--- /dev/null
+// CS0315: The type `short' cannot be used as type parameter `T' in the generic type or method `A<T>'. There is no boxing conversion from `short' to `A<short>.N1<short>'
+// Line: 4
+
+public class A<T> where T : A<short>.N1<T>
+{
+ public class N1<U>
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS0452: The type `int' must be a reference type in order to use it as type parameter `T' in the generic type or method `C<T>'
+// Line: 10
+
+public class C<T> where T : class
+{
+}
+
+class A
+{
+ public A (ref C<int> args)
+ {
+ }
+}
+
--- /dev/null
+// CS0452: The type `int' must be a reference type in order to use it as type parameter `T' in the generic type or method `C<T>'
+// Line: 10
+
+public class C<T> where T : class
+{
+}
+
+delegate C<int> D ();
--- /dev/null
+// CS0452: The type `int' must be a reference type in order to use it as type parameter `T' in the generic type or method `C<T>'
+// Line: 10
+
+public class C<T> where T : class
+{
+}
+
+delegate void D (C<int> arg);
--- /dev/null
+// CS0452: The type `ulong' must be a reference type in order to use it as type parameter `T' in the generic type or method `C<T>'
+// Line: 10
+
+public class C<T> where T : class
+{
+ public int this [params C<ulong>[] args] {
+ set {}
+ }
+}
+
--- /dev/null
+// CS0453: The type `string' must be a non-nullable value type in order to use it as type parameter `T' in the generic type or method `C<T>'
+// Line: 10
+
+public class C<T> where T : struct
+{
+}
+
+class A
+{
+ public C<string> Foo ()
+ {
+ }
+}
+
--- /dev/null
+// CS0453: The type `string' must be a non-nullable value type in order to use it as type parameter `T' in the generic type or method `C<T>'
+// Line: 10
+
+public class C<T> where T : struct
+{
+}
+
+class A
+{
+ public void Foo (C<string>[] args)
+ {
+ }
+}
+
--- /dev/null
+// CS0619: `A' is obsolete: `stop'
+// Line: 11
+
+using System;
+
+[Obsolete ("stop", true)]
+public class A
+{
+}
+
+public class C<T> where T : A
+{
+}
get { return tc; }
}
- public bool HasUnresolvedConstraints {
- get { return true; }
- }
-
public bool IsObsolete {
get { return tc.IsObsolete; }
}
// TODO: passing `this' is wrong, should be base type iface instead
TypeManager.CheckTypeVariance (iface_type, Variance.Covariant, this);
- // TODO: Location is wrong, it should be unresolved iface expr location
- ConstraintChecker.Check (this, iface_type, Location);
-
if (((InflatedTypeSpec) iface_type).HasDynamicArgument () && !IsCompilerGenerated) {
Report.Error (1966, Location,
"`{0}': cannot implement a dynamic interface `{1}'",
}
if (base_type != null) {
+ //
+ // Run checks skipped during FullNamedExpression::ResolveAsType
+ //
if (base_type_expr != null) {
ObsoleteAttribute obsolete_attr = base_type.GetAttributeObsolete ();
if (obsolete_attr != null && !IsObsolete)
AttributeTester.Report_ObsoleteMessage (obsolete_attr, base_type.GetSignatureForError (), base_type_expr.Location, Report);
-
- ConstraintChecker.Check (this, base_type, base_type_expr.Location);
}
if (base_type.Interfaces != null) {
}
}
- if (type_params != null) {
- foreach (var tp in type_params) {
- tp.CheckGenericConstraints ();
- }
- }
-
DefineContainerMembers (constants);
DefineContainerMembers (fields);
}
}
+ // Run constraints check on all possible generic types
+ if ((ModFlags & Modifiers.COMPILER_GENERATED) == 0) {
+ if (base_type != null && base_type_expr != null) {
+ ConstraintChecker.Check (this, base_type, base_type_expr.Location);
+ }
+
+ if (iface_exprs != null) {
+ foreach (var iface_type in iface_exprs) {
+ if (iface_type == null)
+ continue;
+
+ ConstraintChecker.Check (this, iface_type, Location); // TODO: Location is wrong
+ }
+ }
+ }
+
if (all_tp_builders != null) {
int current_starts_index = CurrentTypeParametersStartIndex;
for (int i = 0; i < all_tp_builders.Length; i++) {
if (i < current_starts_index) {
TypeParameters[i].EmitConstraints (all_tp_builders [i]);
} else {
- CurrentTypeParameters [i - current_starts_index].Emit ();
+ var tp = CurrentTypeParameters [i - current_starts_index];
+ tp.CheckGenericConstraints (!IsObsolete);
+ tp.Emit ();
}
}
}
bool IsObsolete { get; }
bool IsUnsafe { get; }
bool IsStatic { get; }
- bool HasUnresolvedConstraints { get; }
string GetSignatureForError ();
get { return (flags & Options.DoFlowAnalysis) != 0; }
}
- public bool HasUnresolvedConstraints {
- get { return false; }
- }
-
public bool IsInProbingMode {
get {
return (flags & Options.ProbingMode) != 0;
if (type.Type != null && type.Type.Kind == MemberKind.Void)
report.Error (620, GetLocation ($3), "`{0}': indexer return type cannot be `void'", indexer.GetSignatureForError ());
- if (indexer.Parameters.IsEmpty) {
+ if (indexer.ParameterInfo.IsEmpty) {
report.Error (1551, GetLocation ($5), "Indexers must have at least one parameter");
}
get { return null; }
}
- public virtual bool HasUnresolvedConstraints {
- get { return false; }
- }
-
public bool IsObsolete {
get {
if (GetAttributeObsolete () != null)
MissingDependency_Undetected = 1 << 4,
MissingDependency = 1 << 5,
HasDynamicElement = 1 << 6,
+ ConstraintsChecked = 1 << 7,
IsAccessor = 1 << 9, // Method is an accessor
IsGeneric = 1 << 10, // Member contains type arguments
return_attributes = new ReturnParameter (this, InvokeBuilder.MethodBuilder, Location);
Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder, ReturnType.Type, Location);
}
+
+ ConstraintChecker.Check (this, ReturnType.Type, ReturnType.Location);
}
Constructor.ParameterInfo.ApplyAttributes (this, Constructor.ConstructorBuilder);
Constructor.ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+ parameters.CheckConstraints (this);
parameters.ApplyAttributes (this, InvokeBuilder.MethodBuilder);
InvokeBuilder.MethodBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
//
// Obsolete checks cannot be done when resolving base context as they
- // require type dependecies to be set but we are just resolving them
+ // require type dependencies to be set but we are in process of resolving them
//
if (!(mc is TypeContainer.BaseContext)) {
ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
Report.Error (625, Location, "`{0}': Instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute", GetSignatureForError ());
}
+ ConstraintChecker.Check (this, member_type, type_expr.Location);
+
base.Emit ();
}
return false;
}
- public void CheckGenericConstraints (IMemberContext context)
+ public void CheckGenericConstraints (IMemberContext context, bool obsoleteCheck)
{
foreach (var c in constraints) {
- if (c != null && c.Type != null) {
- ConstraintChecker.Check (context, c.Type, c.Location);
+ if (c == null)
+ continue;
+
+ var t = c.Type;
+ if (t == null)
+ continue;
+
+ if (obsoleteCheck) {
+ ObsoleteAttribute obsolete_attr = t.GetAttributeObsolete ();
+ if (obsolete_attr != null)
+ AttributeTester.Report_ObsoleteMessage (obsolete_attr, t.GetSignatureForError (), c.Location, context.Module.Compiler.Report);
}
+
+ ConstraintChecker.Check (context, t, c.Location);
}
}
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
}
- public void CheckGenericConstraints ()
+ public void CheckGenericConstraints (bool obsoleteCheck)
{
if (constraints != null)
- constraints.CheckGenericConstraints (this);
+ constraints.CheckGenericConstraints (this, obsoleteCheck);
}
public TypeParameter CreateHoistedCopy (TypeContainer declaringType, TypeSpec declaringSpec)
if (open_type.Kind == MemberKind.MissingType)
MemberCache = MemberCache.Empty;
+
+ if ((open_type.Modifiers & Modifiers.COMPILER_GENERATED) != 0)
+ state |= StateFlags.ConstraintsChecked;
}
#region Properties
}
}
+ //
+ // Used to cache expensive constraints validation on constructed types
+ //
+ public bool HasConstraintsChecked {
+ get {
+ return (state & StateFlags.ConstraintsChecked) != 0;
+ }
+ set {
+ state = value ? state | StateFlags.ConstraintsChecked : state & ~StateFlags.ConstraintsChecked;
+ }
+ }
+
public override IList<TypeSpec> Interfaces {
get {
if (cache == null)
return TypeManager.CSharpName (type);
}
- public override TypeSpec ResolveAsType (IMemberContext ec)
+ public override TypeSpec ResolveAsType (IMemberContext mc)
{
- if (!args.Resolve (ec))
+ if (eclass != ExprClass.Unresolved)
+ return type;
+
+ if (!args.Resolve (mc))
return null;
TypeSpec[] atypes = args.Arguments;
//
// Now bind the parameters
//
- type = open_type.MakeGenericType (ec, atypes);
+ var inflated = open_type.MakeGenericType (mc, atypes);
+ type = inflated;
eclass = ExprClass.Type;
//
- // Check constraints when context is not method/base type
+ // The constraints can be checked only when full type hierarchy is known
//
- if (!ec.HasUnresolvedConstraints)
- ConstraintChecker.Check (ec, type, loc);
+ if (!inflated.HasConstraintsChecked && mc.Module.HasTypesFullyDefined) {
+ var constraints = inflated.Constraints;
+ if (constraints != null) {
+ var cc = new ConstraintChecker (mc);
+ if (cc.CheckAll (open_type, atypes, constraints, loc)) {
+ inflated.HasConstraintsChecked = true;
+ }
+ }
+ }
return type;
}
{
IMemberContext mc;
bool ignore_inferred_dynamic;
+ bool recursive_checks;
public ConstraintChecker (IMemberContext ctx)
{
this.mc = ctx;
ignore_inferred_dynamic = false;
+ recursive_checks = false;
}
#region Properties
//
// Checks the constraints of open generic type against type
- // arguments. Has to be called after all members have been defined
+ // arguments. This version is used for types which could not be
+ // checked immediatelly during construction because the type
+ // hierarchy was not yet fully setup (before Emit phase)
//
public static bool Check (IMemberContext mc, TypeSpec type, Location loc)
{
- if ((type.Modifiers & Modifiers.COMPILER_GENERATED) != 0)
- return true;
+ //
+ // Check declaring type first if there is any
+ //
+ if (type.DeclaringType != null && !Check (mc, type.DeclaringType, loc))
+ return false;
+
+ while (type is ElementTypeSpec)
+ type = ((ElementTypeSpec) type).Element;
if (type.Arity == 0)
return true;
- var gtype = (InflatedTypeSpec) type;
+ var gtype = type as InflatedTypeSpec;
+ if (gtype == null)
+ return true;
+
var constraints = gtype.Constraints;
if (constraints == null)
return true;
- return new ConstraintChecker(mc).CheckAll (type.GetDefinition (), type.TypeArguments, constraints, loc);
+ if (gtype.HasConstraintsChecked)
+ return true;
+
+ var cc = new ConstraintChecker (mc);
+ cc.recursive_checks = true;
+
+ if (cc.CheckAll (gtype.GetDefinition (), type.TypeArguments, constraints, loc)) {
+ gtype.HasConstraintsChecked = true;
+ return true;
+ }
+
+ return false;
}
//
if (ignore_inferred_dynamic && targs[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic)
continue;
- if (!CheckConstraint (context, targs [i], tparams [i], loc))
+ var targ = targs[i];
+ if (!CheckConstraint (context, targ, tparams [i], loc))
+ return false;
+
+ if (!recursive_checks)
+ continue;
+
+ if (!Check (mc, targ, loc))
return false;
}
get { return "M:"; }
}
+ public override void Emit ()
+ {
+ if ((ModFlags & Modifiers.COMPILER_GENERATED) == 0) {
+ parameters.CheckConstraints (this);
+ }
+
+ base.Emit ();
+ }
+
public override bool EnableOverloadChecks (MemberCore overload)
{
if (overload is MethodCore) {
}
}
- if (MethodData != null)
- MethodData.Emit (Parent);
+ if (type_expr != null)
+ ConstraintChecker.Check (this, member_type, type_expr.Location);
base.Emit ();
+ if (MethodData != null)
+ MethodData.Emit (Parent);
+
Block = null;
MethodData = null;
}
}
}
- public override bool HasUnresolvedConstraints {
- get {
- if (CurrentTypeParameters == null)
- return false;
-
- // When overriding base method constraints are fetched from
- // base method but to find it we have to resolve parameters
- // to find exact base method match
- if (IsExplicitImpl || (ModFlags & Modifiers.OVERRIDE) != 0)
- return base_method == null;
-
- // Even for non-override generic method constraints check has to be
- // delayed after all constraints are resolved
- return true;
- }
- }
-
public TypeParameterSpec[] TypeParameters {
get {
// TODO: Cache this
}
if (CurrentTypeParameters != null) {
- ConstraintChecker.Check (this, member_type, type_expr.Location);
-
- for (int i = 0; i < parameters.Count; ++i) {
- ConstraintChecker.Check (this, parameters.Types[i], Location); // TODO: Location is wrong
- }
-
for (int i = 0; i < CurrentTypeParameters.Length; ++i) {
var tp = CurrentTypeParameters [i];
- tp.CheckGenericConstraints ();
+ tp.CheckGenericConstraints (false);
tp.Emit ();
}
}
OptAttributes.Emit ();
base.Emit ();
+ parameters.ApplyAttributes (this, ConstructorBuilder);
//
// If we use a "this (...)" constructor initializer, then
}
}
- parameters.ApplyAttributes (this, ConstructorBuilder);
-
SourceMethod source = SourceMethod.Create (Parent, ConstructorBuilder, block);
if (block != null) {
if (best == null)
return null;
-// if ((best.Modifiers & Modifiers.INTERNAL) != 0 && !best.MemberDefinition.IsInternalAsPublic (ctx.Module.DeclaringAssembly))
-// return null;
-
te = new TypeExpression (best, Location.Null);
// TODO MemberCache: Cache more
get { return SlaveDeclSpace.CurrentTypeParameters; }
}
- // FIXME: It's false for expression types
- public bool HasUnresolvedConstraints {
- get { return true; }
- }
-
public bool IsObsolete {
get { return SlaveDeclSpace.IsObsolete; }
}
null);
}
+ public void CheckConstraints (IMemberContext mc)
+ {
+ foreach (Parameter p in parameters) {
+ //
+ // It's null for compiler generated types or special types like __arglist
+ //
+ if (p.TypeExpression != null)
+ ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
+ }
+ }
+
//
// Returns non-zero value for equal CLS parameter signatures
//
Module.PredefinedAttributes.Dynamic.EmitAttribute (PropertyBuilder, member_type, Location);
}
+ ConstraintChecker.Check (this, member_type, type_expr.Location);
+
first.Emit (Parent);
if (AccessorSecond != null)
AccessorSecond.Emit (Parent);
OptAttributes.Emit ();
}
+ ConstraintChecker.Check (this, member_type, type_expr.Location);
+
Add.Emit (Parent);
Remove.Emit (Parent);
this.parameters = parameters;
}
+ #region Properties
+
+ AParametersCollection IParametersMember.Parameters {
+ get {
+ return parameters;
+ }
+ }
+
+ public ParametersCompiled ParameterInfo {
+ get {
+ return parameters;
+ }
+ }
+
+ #endregion
+
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
if (a.Type == pa.IndexerName) {
return base.EnableOverloadChecks (overload);
}
+ public override void Emit ()
+ {
+ parameters.CheckConstraints (this);
+
+ base.Emit ();
+ }
+
public override string GetSignatureForError ()
{
StringBuilder sb = new StringBuilder (Parent.GetSignatureForError ());
return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation ();
}
- public AParametersCollection Parameters {
- get {
- return parameters;
- }
- }
-
- public ParametersCompiled ParameterInfo {
- get {
- return parameters;
- }
- }
-
protected override bool VerifyClsCompliance ()
{
if (!base.VerifyClsCompliance ())
}
}
+ public bool HasTypesFullyDefined {
+ get; set;
+ }
+
//
// Returns module global:: namespace
//
throw new InternalErrorException (tc, e);
}
}
+
+ HasTypesFullyDefined = true;
}
public override void Emit ()