From c1bfc9f2a7e8d49bdc3644ee233d9d03e299a542 Mon Sep 17 00:00:00 2001 From: Louis-Vincent Boudreault Date: Sun, 10 Nov 2019 10:31:15 -0500 Subject: [PATCH] Fixed safe-call miss cast when reference primitive data types Signed-off-by: Louis-Vincent Boudreault --- src/compiler/abstract_compiler.nit | 20 ++++++++++-- tests/base_safe2.nit | 63 ++++++++++++++++++++++++++++++++++++ tests/sav/base_safe2.res | 5 +++ tests/sav/base_safe2_alt1.res | 1 + 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 tests/base_safe2.nit create mode 100644 tests/sav/base_safe2.res create mode 100644 tests/sav/base_safe2_alt1.res diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 77a20f4..57e738f 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -4390,9 +4390,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 diff --git a/tests/base_safe2.nit b/tests/base_safe2.nit new file mode 100644 index 0000000..2c058df --- /dev/null +++ b/tests/base_safe2.nit @@ -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 index 0000000..1ed892a --- /dev/null +++ b/tests/sav/base_safe2.res @@ -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 index 0000000..f48c476 --- /dev/null +++ b/tests/sav/base_safe2_alt1.res @@ -0,0 +1 @@ +Runtime error: Receiver is null (alt/base_safe2_alt1.nit:39) -- 1.7.9.5