[svn] r7387: nemerle/trunk/ncc/typing: StaticTyVar.n TyVarEnv.n

VladD2 svnadmin at nemerle.org
Tue Feb 6 04:59:38 CET 2007


Log:
Fix 875: Added detection of cyclic constraints.

Author: VladD2
Date: Tue Feb  6 04:59:35 2007
New Revision: 7387

Modified:
   nemerle/trunk/ncc/typing/StaticTyVar.n
   nemerle/trunk/ncc/typing/TyVarEnv.n

Modified: nemerle/trunk/ncc/typing/StaticTyVar.n
==============================================================================
--- nemerle/trunk/ncc/typing/StaticTyVar.n	(original)
+++ nemerle/trunk/ncc/typing/StaticTyVar.n	Tue Feb  6 04:59:35 2007
@@ -136,10 +136,6 @@
             (special & ~GenericParameterAttributes.NotNullableValueTypeConstraint))
         Message.Error ("`struct' generic constraint cannot be used together with `class' or `new ()'");
 
-      foreach (TyVarRef (tv) in subtype)
-        when (tv.Equals (this)) 
-          Message.Error ("cyclic constraint on type variable " + this.ToString ());
-        
       this.special = special;
       Constraints = subtype;
     }

Modified: nemerle/trunk/ncc/typing/TyVarEnv.n
==============================================================================
--- nemerle/trunk/ncc/typing/TyVarEnv.n	(original)
+++ nemerle/trunk/ncc/typing/TyVarEnv.n	Tue Feb  6 04:59:35 2007
@@ -395,6 +395,7 @@
         (map.Replace (name, tv_obj), tv_obj :: the_list)
       }
       def (m, l) = List.FoldLeft (tp.tyvars, (this.tyvars, []), loop);
+      def tyParams = l.Rev();
       def tenv = TyVarEnv (Manager, m);
       tenv.triggerObsolete = this.triggerObsolete;
 
@@ -435,13 +436,75 @@
         }
       }  
       
-      foreach (tv : StaticTyVar in l) {
+      mutable isConstraintsCyclic = false;
+
+
+      def tryDetectCyclicConstraints ()
+      {
+        def graph = Hashtable();
+
+        def tryFindCyclicConstraint (tyRef)
+        {
+          foreach (tv : StaticTyVar in tyParams)
+            graph[tv.id] = false;  // reset 'visited' flags
+
+          def scan (tyRef, path = []) // travers constraint dependency path
+          {
+            mutable visited;
+            if (graph.TryGetValue (tyRef.id, out visited))
+            { // tyRef is type parametr...
+              if (visited)
+                tyRef.Name :: path // and already visited
+              else
+              { // first visit
+                graph[tyRef.id] = true; // mark type parametr as visited
+                mutable constraint;
+                if (constraints.TryGetValue(tyRef.id, out constraint))
+                { // type parametr have constraints... foreach constraint...
+                  foreach (TyVarRef (subTyRef) in constraint[1])
+                  {
+                    def res = scan(subTyRef, path);
+                    unless (res.IsEmpty) // if we find cicle... ignore other...
+                      Nemerle.Imperative.Return (tyRef.Name :: res);
+                  }
+
+                  if (path.IsEmpty) [] else tyRef.Name :: path
+                }
+                else path
+              }
+            }
+            else path
+          }
+
+          def path = scan (tyRef);
+          unless (path.IsEmpty)
+          { // We have cycle! Extract information about it...
+            isConstraintsCyclic = true;
+            def info = path.ToString(" => ");
+            def tyParam = path.Head;
+            Message.Error ( // try find location of type parametr
+              match (tp.tyvars.Find(x => x.ToString() == tyParam)) {
+                | Some(name) => name.Location
+                | _          => Location.Default
+              },
+              $"A constraint of '$tyParam' type parameter is cyclic ($info)");
+          }
+        }
+
+        foreach (tv : StaticTyVar in tyParams)
+          tryFindCyclicConstraint(tv);
+      }
+
+      unless (tyParams.IsEmpty)
+        tryDetectCyclicConstraints ();
+
+      unless (isConstraintsCyclic)
+        foreach (tv : StaticTyVar in tyParams)
         // FIXME: check Intersection invariants and flag error
         // to the user, otherwise we'll get an ICE
         tv.SetConstraints (get (tv.id)); 
-      }
       
-      (tenv, List.Rev (l))
+      (tenv, tyParams)
     }
   }
 }



More information about the svn mailing list