diff dmd/TypeFunction.d @ 135:af1bebfd96a4 dmd2037

dmd 2.038
author Eldar Insafutdinov <e.insafutdinov@gmail.com>
date Mon, 13 Sep 2010 22:19:42 +0100
parents c494af1dba80
children 95b3ed3cddd5
line wrap: on
line diff
--- a/dmd/TypeFunction.d	Sat Sep 11 13:03:39 2010 +0100
+++ b/dmd/TypeFunction.d	Mon Sep 13 22:19:42 2010 +0100
@@ -34,6 +34,7 @@
 import dmd.Util;
 import dmd.FuncDeclaration;
 import dmd.Dsymbol;
+import dmd.TypeTuple;
 import dmd.TemplateInstance : isTuple;
 
 import dmd.backend.TYPE;
@@ -61,6 +62,7 @@
     bool isref;		// true: returns a reference
     LINK linkage;	// calling convention
     TRUST trust;	// level of trust
+    Expressions fargs;	// function arguments
 
     int inuse;
 
@@ -88,6 +90,7 @@
 		t.isproperty = isproperty;
 		t.isref = isref;
         t.trust = trust;
+        t.fargs = fargs;
 
 		return t;
 	}
@@ -136,7 +139,7 @@
 			return this;
 		}
 		//printf("TypeFunction.semantic() this = %p\n", this);
-		//printf("TypeFunction.semantic() %s, sc.stc = %x\n", toChars(), sc.stc);
+		//printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs);
 
 		/* Copy in order to not mess up original.
 		 * This can produce redundant copies if inferring return type,
@@ -174,6 +177,7 @@
 	            }
 	        }
 
+        bool wildreturn = false;
 		if (tf.next)
 		{
 			tf.next = tf.next.semantic(loc,sc);
@@ -197,8 +201,14 @@
 			}
 			if (tf.next.isauto() && !(sc.flags & SCOPE.SCOPEctor))
 				error(loc, "functions cannot return scope %s", tf.next.toChars());
-		}
+	        if (tf.next.toBasetype().ty == TY.Tvoid)
+	            tf.isref = false;			// rewrite "ref void" as just "void"
+	        if (tf.next.isWild())
+	            wildreturn = true;
+        }
 
+        bool wildparams = false;
+        bool wildsubparams = false;
 		if (tf.parameters)
 		{	
 			/* Create a scope for evaluating the default arguments for the parameters
@@ -210,49 +220,97 @@
 			size_t dim = Parameter.dim(tf.parameters);
 
 			for (size_t i = 0; i < dim; i++)
-			{   auto arg = Parameter.getNth(tf.parameters, i);
+			{   auto fparam = Parameter.getNth(tf.parameters, i);
 
 				tf.inuse++;
-				arg.type = arg.type.semantic(loc, argsc);
+				fparam.type = fparam.type.semantic(loc, argsc);
 				if (tf.inuse == 1) tf.inuse--;
 
-				arg.type = arg.type.addStorageClass(arg.storageClass);
+				fparam.type = fparam.type.addStorageClass(fparam.storageClass);
 
-				if (arg.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic))
+				if (fparam.storageClass & (STC.STCauto | STC.STCalias | STC.STCstatic))
 				{
-					if (!arg.type)
+					if (!fparam.type)
 					continue;
 				}
 
-				Type t = arg.type.toBasetype();
+				Type t = fparam.type.toBasetype();
 
-				if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy))
+				if (fparam.storageClass & (STC.STCout | STC.STCref | STC.STClazy))
 				{
 					//if (t.ty == TY.Tsarray)
 						//error(loc, "cannot have out or ref parameter of type %s", t.toChars());
-					if (arg.storageClass & STC.STCout && arg.type.mod & (STCconst | STCimmutable))
+					if (fparam.storageClass & STC.STCout && fparam.type.mod & (STCconst | STCimmutable))
 						error(loc, "cannot have const or immutabl out parameter of type %s", t.toChars());
 				}
-				if (!(arg.storageClass & STC.STClazy) && t.ty == TY.Tvoid)
-					error(loc, "cannot have parameter of type %s", arg.type.toChars());
+				if (!(fparam.storageClass & STC.STClazy) && t.ty == TY.Tvoid)
+					error(loc, "cannot have parameter of type %s", fparam.type.toChars());
 
-				if (arg.defaultArg)
-				{
-					arg.defaultArg = arg.defaultArg.semantic(argsc);
-					arg.defaultArg = resolveProperties(argsc, arg.defaultArg);
-					arg.defaultArg = arg.defaultArg.implicitCastTo(argsc, arg.type);
-				}
+	            if (t.isWild())
+	            {
+		            wildparams = true;
+		            if (tf.next && !wildreturn)
+		                error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')");
+	            }
+	            else if (!wildsubparams && t.hasWild())
+		            wildsubparams = true;
 
-				/* If arg turns out to be a tuple, the number of parameters may
+	            if (fparam.defaultArg)
+	            {
+		            fparam.defaultArg = fparam.defaultArg.semantic(argsc);
+		            fparam.defaultArg = resolveProperties(argsc, fparam.defaultArg);
+		            fparam.defaultArg = fparam.defaultArg.implicitCastTo(argsc, fparam.type);
+	            }
+
+				/* If fparam turns out to be a tuple, the number of parameters may
 				 * change.
 				 */
 				if (t.ty == TY.Ttuple)
-				{	dim = Parameter.dim(tf.parameters);
+	            {
+		        // Propagate storage class from tuple parameters to their element-parameters.
+		            auto tt = cast(TypeTuple)t;
+		            if (tt.arguments)
+		            {
+		                auto tdim = tt.arguments.dim;
+		                foreach (narg; tt.arguments)
+		                {
+			                narg.storageClass = fparam.storageClass;
+		                }
+		            }
+
+		            /* Reset number of parameters, and back up one to do this fparam again,
+		             * now that it is the first element of a tuple
+		             */
+		            dim = Parameter.dim(tf.parameters);
 					i--;
+                    continue;
 				}
+
+	            /* Resolve "auto ref" storage class to be either ref or value,
+	             * based on the argument matching the parameter
+	             */
+	            if (fparam.storageClass & STC.STCauto)
+	            {
+		            if (fargs && i < fargs.dim)
+		            {
+                        auto farg = fargs[i];
+		                if (farg.isLvalue())
+                            {}				// ref parameter
+		                else
+			                fparam.storageClass &= ~STC.STCref;	// value parameter
+		            }
+		            else
+		                error(loc, "auto can only be used for template function parameters");
+	            }
 			}
 			argsc.pop();
 		}
+
+        if (wildreturn && !wildparams)
+	    error(loc, "inout on return means inout must be on a parameter as well for %s", toChars());
+        if (wildsubparams && wildparams)
+	    error(loc, "inout must be all or none on top level for %s", toChars());
+
 		if (tf.next)
 		tf.deco = tf.merge().deco;
 
@@ -287,14 +345,7 @@
 			return;
 		}
 		inuse++;
-static if (true) {
-		if (mod & MOD.MODshared)
-			buf.writeByte('O');
-		if (mod & MOD.MODconst)
-			buf.writeByte('x');
-		else if (mod & MOD.MODinvariant)
-			buf.writeByte('y');
-}
+        MODtoDecoBuffer(buf, mod);
 		switch (linkage)
 		{
 			case LINK.LINKd:		mc = 'F';	break;
@@ -320,7 +371,7 @@
 		            buf.writestring("Ne");
 		            break;
 	            case TRUST.TRUSTsafe:
-		            buf.writestring("Nd");
+		            buf.writestring("Nf");
 		            break;
                 default:
 	        }
@@ -348,12 +399,11 @@
 
 		/* Use 'storage class' style for attributes
 		 */
-		if (mod & MODconst)
-			buf.writestring("const ");
-		if (mod & MODinvariant)
-			buf.writestring("immutable ");
-		if (mod & MODshared)
-			buf.writestring("shared ");
+	    if (mod)
+        {
+	        MODtoBuffer(buf, mod);
+	        buf.writeByte(' ');
+        }
 
 		if (ispure)
 			buf.writestring("pure ");
@@ -569,16 +619,15 @@
 	
     override Type reliesOnTident()
 	{
-		if (parameters)
-		{
-			foreach (arg; parameters)
-			{   
-				Type t = arg.type.reliesOnTident();
-				if (t)
-					return t;
-			}
-		}
-		return next.reliesOnTident();
+        size_t dim = Parameter.dim(parameters);
+        for (size_t i = 0; i < dim; i++)
+        {
+            auto fparam = Parameter.getNth(parameters, i);
+	        Type t = fparam.type.reliesOnTident();
+	        if (t)
+	            return t;
+        }
+        return next ? next.reliesOnTident() : null;
 	}
 
 version (CPP_MANGLE) {
@@ -631,6 +680,8 @@
 	{
 		//printf("TypeFunction.callMatch() %s\n", toChars());
 		MATCH match = MATCH.MATCHexact;		// assume exact match
+        bool exactwildmatch = false;
+        bool wildmatch = false;
 
 		if (ethis)
 		{
@@ -640,7 +691,7 @@
 
 			if (t.mod != mod)
 			{
-				if (mod == MOD.MODconst)
+				if (MODimplicitConv(t.mod, mod))
 					match = MATCH.MATCHconst;
 				else
 					return MATCH.MATCHnomatch;
@@ -690,7 +741,7 @@
 			
 			if (p.storageClass & STCref)
 			{
-				/* Don't allow static arrays to be passed to mutable refereces
+				/* Don't allow static arrays to be passed to mutable references
 				 * to static arrays if the argument cannot be modified.
 				 */
 				Type targb = arg.type.toBasetype();
@@ -698,15 +749,36 @@
 				//writef("%s\n", targb.toChars());
 				//writef("%s\n", tparb.toChars());
 				if (targb.nextOf() && tparb.ty == Tsarray &&
-				    targb.nextOf().mod != tparb.nextOf().mod &&
-				    !tparb.nextOf().isConst())
+				   !MODimplicitConv(targb.nextOf().mod, tparb.nextOf().mod))
 					goto Nomatch;
 			}
 
 			if (p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid && arg.type.ty != TY.Tvoid)
 				m = MATCH.MATCHconvert;
 			else
+            {
 				m = arg.implicitConvTo(p.type);
+	            if (p.type.isWild())
+	            {
+		            if (m == MATCHnomatch)
+		            {
+		                m = arg.implicitConvTo(p.type.constOf());
+		                if (m == MATCHnomatch)
+			            m = arg.implicitConvTo(p.type.sharedConstOf());
+		                if (m != MATCHnomatch)
+			            wildmatch = true;	// mod matched to wild
+		            }
+		            else
+		                exactwildmatch = true;	// wild matched to wild
+
+		            /* If both are allowed, then there could be more than one
+		             * binding of mod to wild, leaving a gaping type hole.
+		             */
+		            if (wildmatch && exactwildmatch)
+		                m = MATCHnomatch;
+	            }
+	        }
+
 			//printf("\tm = %d\n", m);
 			if (m == MATCH.MATCHnomatch)			// if no match
 			{