Merge: Simplify constructors: next episode
authorJean Privat <jean@pryen.org>
Tue, 28 Jan 2020 20:03:47 +0000 (15:03 -0500)
committerJean Privat <jean@pryen.org>
Tue, 28 Jan 2020 20:03:47 +0000 (15:03 -0500)
The current constructors are quite complex, that is why Jean Privat had proposed to simplify them with the pr #1966.

The current init has a double facet, internal with a signature and an empty body and an external one with a signature and initializer represent the attributes to initialize.

This pr replace the external facet by introducing a new constructor defaultinit specific to each class. This default property includes the orchestration of initializers (non-default attributes, autoinit methods, and autoinit annotation in the class). In addition, this property is now the one exposed when a new A is executed.

The current init used to manually set the default constructor it's used to perform a processing after initialization. Note this one must have an empty signature. If this is not the case, an error will be generated.

To use the init in a similar way, we now have to use the old_style_init annotation.

This pr resolve minor bugs and test issues of the Jean's pr .

Pull-Request: #2803
Reviewed-by: Jean Privat <jean@pryen.org>

src/compiler/abstract_compiler.nit
src/rapid_type_analysis.nit
tests/base_safe2.nit [new file with mode: 0644]
tests/sav/base_safe2.res [new file with mode: 0644]
tests/sav/base_safe2_alt1.res [new file with mode: 0644]

index 1f26f6e..e4b8ce6 100644 (file)
@@ -4392,9 +4392,25 @@ redef class ASendExpr
                var res = v.compile_callsite(callsite, args)
                if is_safe then
                        if res != null then
-                               var orig_res = res
+                               # `callsite.mpropdef` may reference a method whose
+                               # return type is a primitive type in C. If it is
+                               # the case, we must convert the primitive type to
+                               # a `val*` to support nullable assignment.
+                               # Autobox's job is to convert primitive type to
+                               # nullable type, eg from `Int` to `nullable `Int`.
+                               # The target type reside in `self.mtype`.
+                               var original_res = v.autobox(res, self.mtype.as(not null))
+
+                               # Here we must create a new_var in case the original
+                               # type is not nullable. We can't call `autobox` to
+                               # convert a complex type to its nullable version.
+                               # eg if we have a type `A`, calling autobox like
+                               # `autobox(A, nullable A)` will return `A` since
+                               # `A` and `nullable A` have the same primitive
+                               # type. The nullable qualifier is only used at
+                               # compile time to add appropriate null checks.
                                res = v.new_var(self.mtype.as(not null))
-                               v.add("{res} = {orig_res};")
+                               v.add("{res} = {original_res};")
                                v.add("\} else \{")
                                v.add("{res} = NULL;")
                        end
index d5bc7d1..404ebce 100644 (file)
@@ -387,7 +387,6 @@ class RapidTypeAnalysis
                                v.enter_visit(npropdef.n_block)
                        end
                end
-
        end
 
        fun add_cast(mtype: MType)
diff --git a/tests/base_safe2.nit b/tests/base_safe2.nit
new file mode 100644 (file)
index 0000000..2c058df
--- /dev/null
@@ -0,0 +1,63 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+redef class Int
+       fun foo do print self
+end
+
+class A
+       var x: Int
+end
+
+class B
+       var a: nullable A = null
+end
+
+class C
+       var x: Int
+       var c: nullable C = null
+end
+
+class D
+       var x: nullable Int
+       var d: nullable D = null
+end
+
+var b = new B
+
+#alt1#b.a?.x.foo
+
+var a = new A(10)
+
+b.a = a
+print "b.a.x: {b.a?.x or else "nothing"}"
+
+var c1 = new C(1)
+var c2 = new C(10)
+var c3 = new C(100)
+c1.c = c2
+c2.c = c3
+
+print c1.c?.c?.x or else "null"
+print c1.c?.c?.c or else "null"
+
+var d1 = new D(1)
+var d2 = new D(10)
+var d3 = new D(null)
+
+d1.d = d2
+d2.d = d3
+
+print d1.d?.x or else "null"
+print d1.d?.d?.x or else "null"
diff --git a/tests/sav/base_safe2.res b/tests/sav/base_safe2.res
new file mode 100644 (file)
index 0000000..1ed892a
--- /dev/null
@@ -0,0 +1,5 @@
+b.a.x: 10
+100
+null
+10
+null
diff --git a/tests/sav/base_safe2_alt1.res b/tests/sav/base_safe2_alt1.res
new file mode 100644 (file)
index 0000000..f48c476
--- /dev/null
@@ -0,0 +1 @@
+Runtime error: Receiver is null (alt/base_safe2_alt1.nit:39)